diff options
author | Paul Mackerras <paulus@samba.org> | 2007-04-29 22:38:01 -0400 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2007-04-29 22:38:01 -0400 |
commit | 49e1900d4cc2e7bcecb681fe60f0990bec2dcce8 (patch) | |
tree | 253801ebf57e0a23856a2c7be129c2c178f62fdf /drivers/media/video | |
parent | 34f6d749c0a328817d5e36274e53121c1db734dc (diff) | |
parent | b9099ff63c75216d6ca10bce5a1abcd9293c27e6 (diff) |
Merge branch 'linux-2.6' into for-2.6.22
Diffstat (limited to 'drivers/media/video')
133 files changed, 17585 insertions, 1966 deletions
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 7a6105153f23..639e8b6c35b1 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig | |||
@@ -647,6 +647,8 @@ config VIDEO_HEXIUM_GEMINI | |||
647 | 647 | ||
648 | source "drivers/media/video/cx88/Kconfig" | 648 | source "drivers/media/video/cx88/Kconfig" |
649 | 649 | ||
650 | source "drivers/media/video/ivtv/Kconfig" | ||
651 | |||
650 | config VIDEO_M32R_AR | 652 | config VIDEO_M32R_AR |
651 | tristate "AR devices" | 653 | tristate "AR devices" |
652 | depends on M32R && VIDEO_V4L1 | 654 | depends on M32R && VIDEO_V4L1 |
@@ -761,6 +763,18 @@ source "drivers/media/video/zc0301/Kconfig" | |||
761 | 763 | ||
762 | source "drivers/media/video/pwc/Kconfig" | 764 | source "drivers/media/video/pwc/Kconfig" |
763 | 765 | ||
766 | config USB_ZR364XX | ||
767 | tristate "USB ZR364XX Camera support" | ||
768 | depends on USB && VIDEO_V4L2 | ||
769 | ---help--- | ||
770 | Say Y here if you want to connect this type of camera to your | ||
771 | computer's USB port. | ||
772 | See <file:Documentation/video4linux/zr364xx.txt> for more info | ||
773 | and list of supported cameras. | ||
774 | |||
775 | To compile this driver as a module, choose M here: the | ||
776 | module will be called zr364xx. | ||
777 | |||
764 | endmenu # V4L USB devices | 778 | endmenu # V4L USB devices |
765 | 779 | ||
766 | endmenu | 780 | endmenu |
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 44ccaed40b49..9c2de501612f 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile | |||
@@ -61,6 +61,7 @@ obj-$(CONFIG_VIDEO_CPIA_USB) += cpia_usb.o | |||
61 | obj-$(CONFIG_VIDEO_MEYE) += meye.o | 61 | obj-$(CONFIG_VIDEO_MEYE) += meye.o |
62 | obj-$(CONFIG_VIDEO_SAA7134) += ir-kbd-i2c.o saa7134/ | 62 | obj-$(CONFIG_VIDEO_SAA7134) += ir-kbd-i2c.o saa7134/ |
63 | obj-$(CONFIG_VIDEO_CX88) += cx88/ | 63 | obj-$(CONFIG_VIDEO_CX88) += cx88/ |
64 | obj-$(CONFIG_VIDEO_IVTV) += ivtv/ | ||
64 | obj-$(CONFIG_VIDEO_EM28XX) += em28xx/ | 65 | obj-$(CONFIG_VIDEO_EM28XX) += em28xx/ |
65 | obj-$(CONFIG_VIDEO_USBVISION) += usbvision/ | 66 | obj-$(CONFIG_VIDEO_USBVISION) += usbvision/ |
66 | obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o | 67 | obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o |
@@ -99,6 +100,7 @@ obj-$(CONFIG_USB_OV511) += ov511.o | |||
99 | obj-$(CONFIG_USB_SE401) += se401.o | 100 | obj-$(CONFIG_USB_SE401) += se401.o |
100 | obj-$(CONFIG_USB_STV680) += stv680.o | 101 | obj-$(CONFIG_USB_STV680) += stv680.o |
101 | obj-$(CONFIG_USB_W9968CF) += w9968cf.o | 102 | obj-$(CONFIG_USB_W9968CF) += w9968cf.o |
103 | obj-$(CONFIG_USB_ZR364XX) += zr364xx.o | ||
102 | 104 | ||
103 | obj-$(CONFIG_USB_SN9C102) += sn9c102/ | 105 | obj-$(CONFIG_USB_SN9C102) += sn9c102/ |
104 | obj-$(CONFIG_USB_ET61X251) += et61x251/ | 106 | obj-$(CONFIG_USB_ET61X251) += et61x251/ |
diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c index 6addc42df045..6b31e50fb951 100644 --- a/drivers/media/video/bt8xx/bttv-cards.c +++ b/drivers/media/video/bt8xx/bttv-cards.c | |||
@@ -291,6 +291,9 @@ static struct CARD { | |||
291 | 291 | ||
292 | { 0x15409511, BTTV_BOARD_ACORP_Y878F, "Acorp Y878F" }, | 292 | { 0x15409511, BTTV_BOARD_ACORP_Y878F, "Acorp Y878F" }, |
293 | 293 | ||
294 | { 0x53534149, BTTV_BOARD_SSAI_SECURITY, "SSAI Security Video Interface" }, | ||
295 | { 0x5353414a, BTTV_BOARD_SSAI_ULTRASOUND, "SSAI Ultrasound Video Interface" }, | ||
296 | |||
294 | /* likely broken, vendor id doesn't match the other magic views ... | 297 | /* likely broken, vendor id doesn't match the other magic views ... |
295 | * { 0xa0fca04f, BTTV_BOARD_MAGICTVIEW063, "Guillemot Maxi TV Video 3" }, */ | 298 | * { 0xa0fca04f, BTTV_BOARD_MAGICTVIEW063, "Guillemot Maxi TV Video 3" }, */ |
296 | 299 | ||
@@ -2907,6 +2910,28 @@ struct tvcard bttv_tvcards[] = { | |||
2907 | .has_radio = 1, | 2910 | .has_radio = 1, |
2908 | .has_remote = 1, | 2911 | .has_remote = 1, |
2909 | }, | 2912 | }, |
2913 | [BTTV_BOARD_SSAI_SECURITY] = { | ||
2914 | .name = "SSAI Security Video Interface", | ||
2915 | .video_inputs = 4, | ||
2916 | .audio_inputs = 0, | ||
2917 | .tuner = -1, | ||
2918 | .svhs = -1, | ||
2919 | .muxsel = { 0, 1, 2, 3 }, | ||
2920 | .tuner_type = -1, | ||
2921 | .tuner_addr = ADDR_UNSET, | ||
2922 | .radio_addr = ADDR_UNSET, | ||
2923 | }, | ||
2924 | [BTTV_BOARD_SSAI_ULTRASOUND] = { | ||
2925 | .name = "SSAI Ultrasound Video Interface", | ||
2926 | .video_inputs = 2, | ||
2927 | .audio_inputs = 0, | ||
2928 | .tuner = -1, | ||
2929 | .svhs = 1, | ||
2930 | .muxsel = { 2, 0, 1, 3 }, | ||
2931 | .tuner_type = -1, | ||
2932 | .tuner_addr = ADDR_UNSET, | ||
2933 | .radio_addr = ADDR_UNSET, | ||
2934 | }, | ||
2910 | }; | 2935 | }; |
2911 | 2936 | ||
2912 | static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards); | 2937 | static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards); |
@@ -2970,20 +2995,20 @@ void __devinit bttv_idcard(struct bttv *btv) | |||
2970 | 2995 | ||
2971 | if (UNSET != audiomux[0]) { | 2996 | if (UNSET != audiomux[0]) { |
2972 | gpiobits = 0; | 2997 | gpiobits = 0; |
2973 | for (i = 0; i < 4; i++) { | 2998 | for (i = 0; i < ARRAY_SIZE(bttv_tvcards->gpiomux); i++) { |
2974 | bttv_tvcards[btv->c.type].gpiomux[i] = audiomux[i]; | 2999 | bttv_tvcards[btv->c.type].gpiomux[i] = audiomux[i]; |
2975 | gpiobits |= audiomux[i]; | 3000 | gpiobits |= audiomux[i]; |
2976 | } | 3001 | } |
2977 | } else { | 3002 | } else { |
2978 | gpiobits = audioall; | 3003 | gpiobits = audioall; |
2979 | for (i = 0; i < 4; i++) { | 3004 | for (i = 0; i < ARRAY_SIZE(bttv_tvcards->gpiomux); i++) { |
2980 | bttv_tvcards[btv->c.type].gpiomux[i] = audioall; | 3005 | bttv_tvcards[btv->c.type].gpiomux[i] = audioall; |
2981 | } | 3006 | } |
2982 | } | 3007 | } |
2983 | bttv_tvcards[btv->c.type].gpiomask = (UNSET != gpiomask) ? gpiomask : gpiobits; | 3008 | bttv_tvcards[btv->c.type].gpiomask = (UNSET != gpiomask) ? gpiomask : gpiobits; |
2984 | printk(KERN_INFO "bttv%d: gpio config override: mask=0x%x, mux=", | 3009 | printk(KERN_INFO "bttv%d: gpio config override: mask=0x%x, mux=", |
2985 | btv->c.nr,bttv_tvcards[btv->c.type].gpiomask); | 3010 | btv->c.nr,bttv_tvcards[btv->c.type].gpiomask); |
2986 | for (i = 0; i < 5; i++) { | 3011 | for (i = 0; i < ARRAY_SIZE(bttv_tvcards->gpiomux); i++) { |
2987 | printk("%s0x%x", i ? "," : "", bttv_tvcards[btv->c.type].gpiomux[i]); | 3012 | printk("%s0x%x", i ? "," : "", bttv_tvcards[btv->c.type].gpiomux[i]); |
2988 | } | 3013 | } |
2989 | printk("\n"); | 3014 | printk("\n"); |
@@ -3638,7 +3663,7 @@ static int __devinit pvr_altera_load(struct bttv *btv, u8 *micro, u32 microlen) | |||
3638 | 3663 | ||
3639 | for (n = 0; n < microlen; n++) { | 3664 | for (n = 0; n < microlen; n++) { |
3640 | bits = micro[n]; | 3665 | bits = micro[n]; |
3641 | for ( i = 0 ; i < 8 ; i++ ) { | 3666 | for (i = 0 ; i < 8 ; i++) { |
3642 | gpio_bits(BTTV_ALT_DCLK,0); | 3667 | gpio_bits(BTTV_ALT_DCLK,0); |
3643 | if (bits & 0x01) | 3668 | if (bits & 0x01) |
3644 | gpio_bits(BTTV_ALT_DATA,BTTV_ALT_DATA); | 3669 | gpio_bits(BTTV_ALT_DATA,BTTV_ALT_DATA); |
@@ -3691,7 +3716,7 @@ static void __devinit osprey_eeprom(struct bttv *btv) | |||
3691 | /* this might be an antique... check for MMAC label in eeprom */ | 3716 | /* this might be an antique... check for MMAC label in eeprom */ |
3692 | if ((ee[0]=='M') && (ee[1]=='M') && (ee[2]=='A') && (ee[3]=='C')) { | 3717 | if ((ee[0]=='M') && (ee[1]=='M') && (ee[2]=='A') && (ee[3]=='C')) { |
3693 | unsigned char checksum = 0; | 3718 | unsigned char checksum = 0; |
3694 | for (i =0; i<21; i++) | 3719 | for (i = 0; i < 21; i++) |
3695 | checksum += ee[i]; | 3720 | checksum += ee[i]; |
3696 | if (checksum != ee[21]) | 3721 | if (checksum != ee[21]) |
3697 | return; | 3722 | return; |
@@ -3703,12 +3728,13 @@ static void __devinit osprey_eeprom(struct bttv *btv) | |||
3703 | unsigned short type; | 3728 | unsigned short type; |
3704 | int offset = 4*16; | 3729 | int offset = 4*16; |
3705 | 3730 | ||
3706 | for(; offset < 8*16; offset += 16) { | 3731 | for (; offset < 8*16; offset += 16) { |
3707 | unsigned short checksum = 0; | 3732 | unsigned short checksum = 0; |
3708 | /* verify the checksum */ | 3733 | /* verify the checksum */ |
3709 | for(i = 0; i<14; i++) checksum += ee[i+offset]; | 3734 | for (i = 0; i < 14; i++) |
3710 | checksum = ~checksum; /* no idea why */ | 3735 | checksum += ee[i+offset]; |
3711 | if ((((checksum>>8)&0x0FF) == ee[offset+14]) && | 3736 | checksum = ~checksum; /* no idea why */ |
3737 | if ((((checksum>>8)&0x0FF) == ee[offset+14]) && | ||
3712 | ((checksum & 0x0FF) == ee[offset+15])) { | 3738 | ((checksum & 0x0FF) == ee[offset+15])) { |
3713 | break; | 3739 | break; |
3714 | } | 3740 | } |
@@ -3721,7 +3747,6 @@ static void __devinit osprey_eeprom(struct bttv *btv) | |||
3721 | type = (ee[offset+4]<<8) | (ee[offset+5]); | 3747 | type = (ee[offset+4]<<8) | (ee[offset+5]); |
3722 | 3748 | ||
3723 | switch(type) { | 3749 | switch(type) { |
3724 | |||
3725 | /* 848 based */ | 3750 | /* 848 based */ |
3726 | case 0x0004: | 3751 | case 0x0004: |
3727 | btv->c.type = BTTV_BOARD_OSPREY1x0_848; | 3752 | btv->c.type = BTTV_BOARD_OSPREY1x0_848; |
@@ -4149,8 +4174,7 @@ static int tea5757_read(struct bttv *btv) | |||
4149 | } | 4174 | } |
4150 | 4175 | ||
4151 | dprintk("bttv%d: tea5757:",btv->c.nr); | 4176 | dprintk("bttv%d: tea5757:",btv->c.nr); |
4152 | for(i = 0; i < 24; i++) | 4177 | for (i = 0; i < 24; i++) { |
4153 | { | ||
4154 | udelay(5); | 4178 | udelay(5); |
4155 | bus_high(btv,btv->mbox_clk); | 4179 | bus_high(btv,btv->mbox_clk); |
4156 | udelay(5); | 4180 | udelay(5); |
@@ -4182,8 +4206,7 @@ static int tea5757_write(struct bttv *btv, int value) | |||
4182 | dprintk("bttv%d: tea5757: write 0x%X\n", btv->c.nr, value); | 4206 | dprintk("bttv%d: tea5757: write 0x%X\n", btv->c.nr, value); |
4183 | bus_low(btv,btv->mbox_clk); | 4207 | bus_low(btv,btv->mbox_clk); |
4184 | bus_high(btv,btv->mbox_we); | 4208 | bus_high(btv,btv->mbox_we); |
4185 | for(i = 0; i < 25; i++) | 4209 | for (i = 0; i < 25; i++) { |
4186 | { | ||
4187 | if (reg & 0x1000000) | 4210 | if (reg & 0x1000000) |
4188 | bus_high(btv,btv->mbox_data); | 4211 | bus_high(btv,btv->mbox_data); |
4189 | else | 4212 | else |
@@ -4755,7 +4778,7 @@ static void kodicom4400r_init(struct bttv *btv) | |||
4755 | gpio_write(1 << 9); /* reset MUX */ | 4778 | gpio_write(1 << 9); /* reset MUX */ |
4756 | gpio_write(0); | 4779 | gpio_write(0); |
4757 | /* Preset camera 0 to the 4 controllers */ | 4780 | /* Preset camera 0 to the 4 controllers */ |
4758 | for (ix=0; ix<4; ix++) { | 4781 | for (ix = 0; ix < 4; ix++) { |
4759 | sw_status[ix] = ix; | 4782 | sw_status[ix] = ix; |
4760 | kodicom4400r_write(btv, ix, ix, 1); | 4783 | kodicom4400r_write(btv, ix, ix, 1); |
4761 | } | 4784 | } |
diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index 5720b77ac9a7..1c38723d3169 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c | |||
@@ -164,6 +164,24 @@ static ssize_t show_card(struct class_device *cd, char *buf) | |||
164 | static CLASS_DEVICE_ATTR(card, S_IRUGO, show_card, NULL); | 164 | static CLASS_DEVICE_ATTR(card, S_IRUGO, show_card, NULL); |
165 | 165 | ||
166 | /* ----------------------------------------------------------------------- */ | 166 | /* ----------------------------------------------------------------------- */ |
167 | /* dvb auto-load setup */ | ||
168 | #if defined(CONFIG_MODULES) && defined(MODULE) | ||
169 | static void request_module_async(struct work_struct *work) | ||
170 | { | ||
171 | request_module("dvb-bt8xx"); | ||
172 | } | ||
173 | |||
174 | static void request_modules(struct bttv *dev) | ||
175 | { | ||
176 | INIT_WORK(&dev->request_module_wk, request_module_async); | ||
177 | schedule_work(&dev->request_module_wk); | ||
178 | } | ||
179 | #else | ||
180 | #define request_modules(dev) | ||
181 | #endif /* CONFIG_MODULES */ | ||
182 | |||
183 | |||
184 | /* ----------------------------------------------------------------------- */ | ||
167 | /* static data */ | 185 | /* static data */ |
168 | 186 | ||
169 | /* special timing tables from conexant... */ | 187 | /* special timing tables from conexant... */ |
@@ -4769,9 +4787,11 @@ static int __devinit bttv_probe(struct pci_dev *dev, | |||
4769 | disclaim_video_lines(btv); | 4787 | disclaim_video_lines(btv); |
4770 | } | 4788 | } |
4771 | 4789 | ||
4772 | /* add subdevices */ | 4790 | /* add subdevices and autoload dvb-bt8xx if needed */ |
4773 | if (bttv_tvcards[btv->c.type].has_dvb) | 4791 | if (bttv_tvcards[btv->c.type].has_dvb) { |
4774 | bttv_sub_add_device(&btv->c, "dvb"); | 4792 | bttv_sub_add_device(&btv->c, "dvb"); |
4793 | request_modules(btv); | ||
4794 | } | ||
4775 | 4795 | ||
4776 | bttv_input_init(btv); | 4796 | bttv_input_init(btv); |
4777 | 4797 | ||
diff --git a/drivers/media/video/bt8xx/bttv-gpio.c b/drivers/media/video/bt8xx/bttv-gpio.c index ba081f6f8c82..84154c26f9c5 100644 --- a/drivers/media/video/bt8xx/bttv-gpio.c +++ b/drivers/media/video/bt8xx/bttv-gpio.c | |||
@@ -71,7 +71,6 @@ struct bus_type bttv_sub_bus_type = { | |||
71 | .probe = bttv_sub_probe, | 71 | .probe = bttv_sub_probe, |
72 | .remove = bttv_sub_remove, | 72 | .remove = bttv_sub_remove, |
73 | }; | 73 | }; |
74 | EXPORT_SYMBOL(bttv_sub_bus_type); | ||
75 | 74 | ||
76 | static void release_sub_device(struct device *dev) | 75 | static void release_sub_device(struct device *dev) |
77 | { | 76 | { |
@@ -152,7 +151,6 @@ void bttv_gpio_inout(struct bttv_core *core, u32 mask, u32 outbits) | |||
152 | btwrite(data,BT848_GPIO_OUT_EN); | 151 | btwrite(data,BT848_GPIO_OUT_EN); |
153 | spin_unlock_irqrestore(&btv->gpio_lock,flags); | 152 | spin_unlock_irqrestore(&btv->gpio_lock,flags); |
154 | } | 153 | } |
155 | EXPORT_SYMBOL(bttv_gpio_inout); | ||
156 | 154 | ||
157 | u32 bttv_gpio_read(struct bttv_core *core) | 155 | u32 bttv_gpio_read(struct bttv_core *core) |
158 | { | 156 | { |
@@ -162,7 +160,6 @@ u32 bttv_gpio_read(struct bttv_core *core) | |||
162 | value = btread(BT848_GPIO_DATA); | 160 | value = btread(BT848_GPIO_DATA); |
163 | return value; | 161 | return value; |
164 | } | 162 | } |
165 | EXPORT_SYMBOL(bttv_gpio_read); | ||
166 | 163 | ||
167 | void bttv_gpio_write(struct bttv_core *core, u32 value) | 164 | void bttv_gpio_write(struct bttv_core *core, u32 value) |
168 | { | 165 | { |
@@ -170,7 +167,6 @@ void bttv_gpio_write(struct bttv_core *core, u32 value) | |||
170 | 167 | ||
171 | btwrite(value,BT848_GPIO_DATA); | 168 | btwrite(value,BT848_GPIO_DATA); |
172 | } | 169 | } |
173 | EXPORT_SYMBOL(bttv_gpio_write); | ||
174 | 170 | ||
175 | void bttv_gpio_bits(struct bttv_core *core, u32 mask, u32 bits) | 171 | void bttv_gpio_bits(struct bttv_core *core, u32 mask, u32 bits) |
176 | { | 172 | { |
@@ -185,7 +181,6 @@ void bttv_gpio_bits(struct bttv_core *core, u32 mask, u32 bits) | |||
185 | btwrite(data,BT848_GPIO_DATA); | 181 | btwrite(data,BT848_GPIO_DATA); |
186 | spin_unlock_irqrestore(&btv->gpio_lock,flags); | 182 | spin_unlock_irqrestore(&btv->gpio_lock,flags); |
187 | } | 183 | } |
188 | EXPORT_SYMBOL(bttv_gpio_bits); | ||
189 | 184 | ||
190 | /* | 185 | /* |
191 | * Local variables: | 186 | * Local variables: |
diff --git a/drivers/media/video/bt8xx/bttv-i2c.c b/drivers/media/video/bt8xx/bttv-i2c.c index 62b873076e09..0dfa49b66418 100644 --- a/drivers/media/video/bt8xx/bttv-i2c.c +++ b/drivers/media/video/bt8xx/bttv-i2c.c | |||
@@ -412,7 +412,7 @@ static void do_i2c_scan(char *name, struct i2c_client *c) | |||
412 | unsigned char buf; | 412 | unsigned char buf; |
413 | int i,rc; | 413 | int i,rc; |
414 | 414 | ||
415 | for (i = 0; i < 128; i++) { | 415 | for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) { |
416 | c->addr = i; | 416 | c->addr = i; |
417 | rc = i2c_master_recv(c,&buf,0); | 417 | rc = i2c_master_recv(c,&buf,0); |
418 | if (rc < 0) | 418 | if (rc < 0) |
diff --git a/drivers/media/video/bt8xx/bttv-if.c b/drivers/media/video/bt8xx/bttv-if.c index 19b564ab0e92..ecf07988cd33 100644 --- a/drivers/media/video/bt8xx/bttv-if.c +++ b/drivers/media/video/bt8xx/bttv-if.c | |||
@@ -33,32 +33,16 @@ | |||
33 | 33 | ||
34 | #include "bttvp.h" | 34 | #include "bttvp.h" |
35 | 35 | ||
36 | EXPORT_SYMBOL(bttv_get_cardinfo); | ||
37 | EXPORT_SYMBOL(bttv_get_pcidev); | 36 | EXPORT_SYMBOL(bttv_get_pcidev); |
38 | EXPORT_SYMBOL(bttv_get_id); | ||
39 | EXPORT_SYMBOL(bttv_gpio_enable); | 37 | EXPORT_SYMBOL(bttv_gpio_enable); |
40 | EXPORT_SYMBOL(bttv_read_gpio); | 38 | EXPORT_SYMBOL(bttv_read_gpio); |
41 | EXPORT_SYMBOL(bttv_write_gpio); | 39 | EXPORT_SYMBOL(bttv_write_gpio); |
42 | EXPORT_SYMBOL(bttv_get_gpio_queue); | ||
43 | EXPORT_SYMBOL(bttv_i2c_call); | ||
44 | 40 | ||
45 | /* ----------------------------------------------------------------------- */ | 41 | /* ----------------------------------------------------------------------- */ |
46 | /* Exported functions - for other modules which want to access the */ | 42 | /* Exported functions - for other modules which want to access the */ |
47 | /* gpio ports (IR for example) */ | 43 | /* gpio ports (IR for example) */ |
48 | /* see bttv.h for comments */ | 44 | /* see bttv.h for comments */ |
49 | 45 | ||
50 | int bttv_get_cardinfo(unsigned int card, int *type, unsigned *cardid) | ||
51 | { | ||
52 | printk("The bttv_* interface is obsolete and will go away,\n" | ||
53 | "please use the new, sysfs based interface instead.\n"); | ||
54 | if (card >= bttv_num) { | ||
55 | return -1; | ||
56 | } | ||
57 | *type = bttvs[card].c.type; | ||
58 | *cardid = bttvs[card].cardid; | ||
59 | return 0; | ||
60 | } | ||
61 | |||
62 | struct pci_dev* bttv_get_pcidev(unsigned int card) | 46 | struct pci_dev* bttv_get_pcidev(unsigned int card) |
63 | { | 47 | { |
64 | if (card >= bttv_num) | 48 | if (card >= bttv_num) |
@@ -66,16 +50,6 @@ struct pci_dev* bttv_get_pcidev(unsigned int card) | |||
66 | return bttvs[card].c.pci; | 50 | return bttvs[card].c.pci; |
67 | } | 51 | } |
68 | 52 | ||
69 | int bttv_get_id(unsigned int card) | ||
70 | { | ||
71 | printk("The bttv_* interface is obsolete and will go away,\n" | ||
72 | "please use the new, sysfs based interface instead.\n"); | ||
73 | if (card >= bttv_num) { | ||
74 | return -1; | ||
75 | } | ||
76 | return bttvs[card].c.type; | ||
77 | } | ||
78 | |||
79 | 53 | ||
80 | int bttv_gpio_enable(unsigned int card, unsigned long mask, unsigned long data) | 54 | int bttv_gpio_enable(unsigned int card, unsigned long mask, unsigned long data) |
81 | { | 55 | { |
@@ -130,28 +104,6 @@ int bttv_write_gpio(unsigned int card, unsigned long mask, unsigned long data) | |||
130 | return 0; | 104 | return 0; |
131 | } | 105 | } |
132 | 106 | ||
133 | wait_queue_head_t* bttv_get_gpio_queue(unsigned int card) | ||
134 | { | ||
135 | struct bttv *btv; | ||
136 | |||
137 | if (card >= bttv_num) { | ||
138 | return NULL; | ||
139 | } | ||
140 | |||
141 | btv = &bttvs[card]; | ||
142 | if (bttvs[card].shutdown) { | ||
143 | return NULL; | ||
144 | } | ||
145 | return &btv->gpioq; | ||
146 | } | ||
147 | |||
148 | void bttv_i2c_call(unsigned int card, unsigned int cmd, void *arg) | ||
149 | { | ||
150 | if (card >= bttv_num) | ||
151 | return; | ||
152 | bttv_call_i2c_clients(&bttvs[card], cmd, arg); | ||
153 | } | ||
154 | |||
155 | /* | 107 | /* |
156 | * Local variables: | 108 | * Local variables: |
157 | * c-basic-offset: 8 | 109 | * c-basic-offset: 8 |
diff --git a/drivers/media/video/bt8xx/bttv.h b/drivers/media/video/bt8xx/bttv.h index 5491acbdaf63..f821ba69db99 100644 --- a/drivers/media/video/bt8xx/bttv.h +++ b/drivers/media/video/bt8xx/bttv.h | |||
@@ -168,6 +168,8 @@ | |||
168 | #define BTTV_BOARD_SABRENT_TVFM 0x8e | 168 | #define BTTV_BOARD_SABRENT_TVFM 0x8e |
169 | #define BTTV_BOARD_HAUPPAUGE_IMPACTVCB 0x8f | 169 | #define BTTV_BOARD_HAUPPAUGE_IMPACTVCB 0x8f |
170 | #define BTTV_BOARD_MACHTV_MAGICTV 0x90 | 170 | #define BTTV_BOARD_MACHTV_MAGICTV 0x90 |
171 | #define BTTV_BOARD_SSAI_SECURITY 0x91 | ||
172 | #define BTTV_BOARD_SSAI_ULTRASOUND 0x92 | ||
171 | 173 | ||
172 | /* more card-specific defines */ | 174 | /* more card-specific defines */ |
173 | #define PT2254_L_CHANNEL 0x10 | 175 | #define PT2254_L_CHANNEL 0x10 |
@@ -260,17 +262,8 @@ extern int bttv_handle_chipset(struct bttv *btv); | |||
260 | /* this obsolete -- please use the sysfs-based | 262 | /* this obsolete -- please use the sysfs-based |
261 | interface below for new code */ | 263 | interface below for new code */ |
262 | 264 | ||
263 | /* returns card type + card ID (for bt878-based ones) | ||
264 | for possible values see lines below beginning with #define BTTV_BOARD_UNKNOWN | ||
265 | returns negative value if error occurred | ||
266 | */ | ||
267 | extern int bttv_get_cardinfo(unsigned int card, int *type, | ||
268 | unsigned int *cardid); | ||
269 | extern struct pci_dev* bttv_get_pcidev(unsigned int card); | 265 | extern struct pci_dev* bttv_get_pcidev(unsigned int card); |
270 | 266 | ||
271 | /* obsolete, use bttv_get_cardinfo instead */ | ||
272 | extern int bttv_get_id(unsigned int card); | ||
273 | |||
274 | /* sets GPOE register (BT848_GPIO_OUT_EN) to new value: | 267 | /* sets GPOE register (BT848_GPIO_OUT_EN) to new value: |
275 | data | (current_GPOE_value & ~mask) | 268 | data | (current_GPOE_value & ~mask) |
276 | returns negative value if error occurred | 269 | returns negative value if error occurred |
@@ -290,20 +283,6 @@ extern int bttv_read_gpio(unsigned int card, unsigned long *data); | |||
290 | extern int bttv_write_gpio(unsigned int card, | 283 | extern int bttv_write_gpio(unsigned int card, |
291 | unsigned long mask, unsigned long data); | 284 | unsigned long mask, unsigned long data); |
292 | 285 | ||
293 | /* returns pointer to task queue which can be used as parameter to | ||
294 | interruptible_sleep_on | ||
295 | in interrupt handler if BT848_INT_GPINT bit is set - this queue is activated | ||
296 | (wake_up_interruptible) and following call to the function bttv_read_gpio | ||
297 | should return new value of GPDATA, | ||
298 | returns NULL value if error occurred or queue is not available | ||
299 | WARNING: because there is no buffer for GPIO data, one MUST | ||
300 | process data ASAP | ||
301 | */ | ||
302 | extern wait_queue_head_t* bttv_get_gpio_queue(unsigned int card); | ||
303 | |||
304 | /* call i2c clients | ||
305 | */ | ||
306 | extern void bttv_i2c_call(unsigned int card, unsigned int cmd, void *arg); | ||
307 | 286 | ||
308 | 287 | ||
309 | 288 | ||
diff --git a/drivers/media/video/bt8xx/bttvp.h b/drivers/media/video/bt8xx/bttvp.h index ad79b8d53430..8f44f02029be 100644 --- a/drivers/media/video/bt8xx/bttvp.h +++ b/drivers/media/video/bt8xx/bttvp.h | |||
@@ -434,6 +434,9 @@ struct bttv { | |||
434 | unsigned int users; | 434 | unsigned int users; |
435 | struct bttv_fh init; | 435 | struct bttv_fh init; |
436 | 436 | ||
437 | /* used to make dvb-bt8xx autoloadable */ | ||
438 | struct work_struct request_module_wk; | ||
439 | |||
437 | /* Default (0) and current (1) video capturing and overlay | 440 | /* Default (0) and current (1) video capturing and overlay |
438 | cropping parameters in bttv_tvnorm.cropcap units. Protected | 441 | cropping parameters in bttv_tvnorm.cropcap units. Protected |
439 | by bttv.lock. */ | 442 | by bttv.lock. */ |
diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c index 710c11a68296..96254dbaf625 100644 --- a/drivers/media/video/cafe_ccic.c +++ b/drivers/media/video/cafe_ccic.c | |||
@@ -4,6 +4,7 @@ | |||
4 | * sensor. | 4 | * sensor. |
5 | * | 5 | * |
6 | * Copyright 2006 One Laptop Per Child Association, Inc. | 6 | * Copyright 2006 One Laptop Per Child Association, Inc. |
7 | * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net> | ||
7 | * | 8 | * |
8 | * Written by Jonathan Corbet, corbet@lwn.net. | 9 | * Written by Jonathan Corbet, corbet@lwn.net. |
9 | * | 10 | * |
@@ -22,6 +23,7 @@ | |||
22 | #include <linux/spinlock.h> | 23 | #include <linux/spinlock.h> |
23 | #include <linux/videodev2.h> | 24 | #include <linux/videodev2.h> |
24 | #include <media/v4l2-common.h> | 25 | #include <media/v4l2-common.h> |
26 | #include <media/v4l2-chip-ident.h> | ||
25 | #include <linux/device.h> | 27 | #include <linux/device.h> |
26 | #include <linux/wait.h> | 28 | #include <linux/wait.h> |
27 | #include <linux/list.h> | 29 | #include <linux/list.h> |
@@ -36,7 +38,7 @@ | |||
36 | 38 | ||
37 | #include "cafe_ccic-regs.h" | 39 | #include "cafe_ccic-regs.h" |
38 | 40 | ||
39 | #define CAFE_VERSION 0x000001 | 41 | #define CAFE_VERSION 0x000002 |
40 | 42 | ||
41 | 43 | ||
42 | /* | 44 | /* |
@@ -164,7 +166,7 @@ struct cafe_camera | |||
164 | struct tasklet_struct s_tasklet; | 166 | struct tasklet_struct s_tasklet; |
165 | 167 | ||
166 | /* Current operating parameters */ | 168 | /* Current operating parameters */ |
167 | enum v4l2_chip_ident sensor_type; /* Currently ov7670 only */ | 169 | u32 sensor_type; /* Currently ov7670 only */ |
168 | struct v4l2_pix_format pix_format; | 170 | struct v4l2_pix_format pix_format; |
169 | 171 | ||
170 | /* Locks */ | 172 | /* Locks */ |
@@ -704,7 +706,13 @@ static void cafe_ctlr_init(struct cafe_camera *cam) | |||
704 | cafe_reg_write(cam, REG_GL_CSR, GCSR_SRS|GCSR_MRS); /* Needed? */ | 706 | cafe_reg_write(cam, REG_GL_CSR, GCSR_SRS|GCSR_MRS); /* Needed? */ |
705 | cafe_reg_write(cam, REG_GL_CSR, GCSR_SRC|GCSR_MRC); | 707 | cafe_reg_write(cam, REG_GL_CSR, GCSR_SRC|GCSR_MRC); |
706 | cafe_reg_write(cam, REG_GL_CSR, GCSR_SRC|GCSR_MRS); | 708 | cafe_reg_write(cam, REG_GL_CSR, GCSR_SRC|GCSR_MRS); |
709 | /* | ||
710 | * Here we must wait a bit for the controller to come around. | ||
711 | */ | ||
712 | spin_unlock_irqrestore(&cam->dev_lock, flags); | ||
707 | mdelay(5); /* FIXME revisit this */ | 713 | mdelay(5); /* FIXME revisit this */ |
714 | spin_lock_irqsave(&cam->dev_lock, flags); | ||
715 | |||
708 | cafe_reg_write(cam, REG_GL_CSR, GCSR_CCIC_EN|GCSR_SRC|GCSR_MRC); | 716 | cafe_reg_write(cam, REG_GL_CSR, GCSR_CCIC_EN|GCSR_SRC|GCSR_MRC); |
709 | cafe_reg_set_bit(cam, REG_GL_IMASK, GIMSK_CCIC_EN); | 717 | cafe_reg_set_bit(cam, REG_GL_IMASK, GIMSK_CCIC_EN); |
710 | /* | 718 | /* |
@@ -772,9 +780,9 @@ static void cafe_ctlr_power_up(struct cafe_camera *cam) | |||
772 | * Control 1 is power down, set to 0 to operate. | 780 | * Control 1 is power down, set to 0 to operate. |
773 | */ | 781 | */ |
774 | cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN); /* pwr up, reset */ | 782 | cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN); /* pwr up, reset */ |
775 | mdelay(1); /* Marvell says 1ms will do it */ | 783 | // mdelay(1); /* Marvell says 1ms will do it */ |
776 | cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C0); | 784 | cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C0); |
777 | mdelay(1); /* Enough? */ | 785 | // mdelay(1); /* Enough? */ |
778 | spin_unlock_irqrestore(&cam->dev_lock, flags); | 786 | spin_unlock_irqrestore(&cam->dev_lock, flags); |
779 | } | 787 | } |
780 | 788 | ||
@@ -818,6 +826,7 @@ static int __cafe_cam_reset(struct cafe_camera *cam) | |||
818 | */ | 826 | */ |
819 | static int cafe_cam_init(struct cafe_camera *cam) | 827 | static int cafe_cam_init(struct cafe_camera *cam) |
820 | { | 828 | { |
829 | struct v4l2_chip_ident chip = { V4L2_CHIP_MATCH_I2C_ADDR, 0, 0, 0 }; | ||
821 | int ret; | 830 | int ret; |
822 | 831 | ||
823 | mutex_lock(&cam->s_mutex); | 832 | mutex_lock(&cam->s_mutex); |
@@ -827,9 +836,11 @@ static int cafe_cam_init(struct cafe_camera *cam) | |||
827 | ret = __cafe_cam_reset(cam); | 836 | ret = __cafe_cam_reset(cam); |
828 | if (ret) | 837 | if (ret) |
829 | goto out; | 838 | goto out; |
830 | ret = __cafe_cam_cmd(cam, VIDIOC_INT_G_CHIP_IDENT, &cam->sensor_type); | 839 | chip.match_chip = cam->sensor->addr; |
840 | ret = __cafe_cam_cmd(cam, VIDIOC_G_CHIP_IDENT, &chip); | ||
831 | if (ret) | 841 | if (ret) |
832 | goto out; | 842 | goto out; |
843 | cam->sensor_type = chip.ident; | ||
833 | // if (cam->sensor->addr != OV7xx0_SID) { | 844 | // if (cam->sensor->addr != OV7xx0_SID) { |
834 | if (cam->sensor_type != V4L2_IDENT_OV7670) { | 845 | if (cam->sensor_type != V4L2_IDENT_OV7670) { |
835 | cam_err(cam, "Unsupported sensor type %d", cam->sensor->addr); | 846 | cam_err(cam, "Unsupported sensor type %d", cam->sensor->addr); |
@@ -1792,18 +1803,19 @@ static void cafe_frame_tasklet(unsigned long data) | |||
1792 | if (list_empty(&cam->sb_avail)) | 1803 | if (list_empty(&cam->sb_avail)) |
1793 | break; /* Leave it valid, hope for better later */ | 1804 | break; /* Leave it valid, hope for better later */ |
1794 | clear_bit(bufno, &cam->flags); | 1805 | clear_bit(bufno, &cam->flags); |
1795 | /* | ||
1796 | * We could perhaps drop the spinlock during this | ||
1797 | * big copy. Something to consider. | ||
1798 | */ | ||
1799 | sbuf = list_entry(cam->sb_avail.next, | 1806 | sbuf = list_entry(cam->sb_avail.next, |
1800 | struct cafe_sio_buffer, list); | 1807 | struct cafe_sio_buffer, list); |
1808 | /* | ||
1809 | * Drop the lock during the big copy. This *should* be safe... | ||
1810 | */ | ||
1811 | spin_unlock_irqrestore(&cam->dev_lock, flags); | ||
1801 | memcpy(sbuf->buffer, cam->dma_bufs[bufno], | 1812 | memcpy(sbuf->buffer, cam->dma_bufs[bufno], |
1802 | cam->pix_format.sizeimage); | 1813 | cam->pix_format.sizeimage); |
1803 | sbuf->v4lbuf.bytesused = cam->pix_format.sizeimage; | 1814 | sbuf->v4lbuf.bytesused = cam->pix_format.sizeimage; |
1804 | sbuf->v4lbuf.sequence = cam->buf_seq[bufno]; | 1815 | sbuf->v4lbuf.sequence = cam->buf_seq[bufno]; |
1805 | sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_QUEUED; | 1816 | sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_QUEUED; |
1806 | sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_DONE; | 1817 | sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_DONE; |
1818 | spin_lock_irqsave(&cam->dev_lock, flags); | ||
1807 | list_move_tail(&sbuf->list, &cam->sb_full); | 1819 | list_move_tail(&sbuf->list, &cam->sb_full); |
1808 | } | 1820 | } |
1809 | if (! list_empty(&cam->sb_full)) | 1821 | if (! list_empty(&cam->sb_full)) |
@@ -2107,6 +2119,7 @@ static int cafe_pci_probe(struct pci_dev *pdev, | |||
2107 | cam->v4ldev = cafe_v4l_template; | 2119 | cam->v4ldev = cafe_v4l_template; |
2108 | cam->v4ldev.debug = 0; | 2120 | cam->v4ldev.debug = 0; |
2109 | // cam->v4ldev.debug = V4L2_DEBUG_IOCTL_ARG; | 2121 | // cam->v4ldev.debug = V4L2_DEBUG_IOCTL_ARG; |
2122 | cam->v4ldev.dev = &pdev->dev; | ||
2110 | ret = video_register_device(&cam->v4ldev, VFL_TYPE_GRABBER, -1); | 2123 | ret = video_register_device(&cam->v4ldev, VFL_TYPE_GRABBER, -1); |
2111 | if (ret) | 2124 | if (ret) |
2112 | goto out_smbus; | 2125 | goto out_smbus; |
@@ -2176,10 +2189,52 @@ static void cafe_pci_remove(struct pci_dev *pdev) | |||
2176 | } | 2189 | } |
2177 | 2190 | ||
2178 | 2191 | ||
2192 | #ifdef CONFIG_PM | ||
2193 | /* | ||
2194 | * Basic power management. | ||
2195 | */ | ||
2196 | static int cafe_pci_suspend(struct pci_dev *pdev, pm_message_t state) | ||
2197 | { | ||
2198 | struct cafe_camera *cam = cafe_find_by_pdev(pdev); | ||
2199 | int ret; | ||
2200 | |||
2201 | ret = pci_save_state(pdev); | ||
2202 | if (ret) | ||
2203 | return ret; | ||
2204 | cafe_ctlr_stop_dma(cam); | ||
2205 | cafe_ctlr_power_down(cam); | ||
2206 | pci_disable_device(pdev); | ||
2207 | return 0; | ||
2208 | } | ||
2209 | |||
2210 | |||
2211 | static int cafe_pci_resume(struct pci_dev *pdev) | ||
2212 | { | ||
2213 | struct cafe_camera *cam = cafe_find_by_pdev(pdev); | ||
2214 | int ret = 0; | ||
2215 | |||
2216 | ret = pci_restore_state(pdev); | ||
2217 | if (ret) | ||
2218 | return ret; | ||
2219 | ret = pci_enable_device(pdev); | ||
2220 | if (ret) { | ||
2221 | cam_warn(cam, "Unable to re-enable device on resume!\n"); | ||
2222 | return ret; | ||
2223 | } | ||
2224 | cafe_ctlr_init(cam); | ||
2225 | cafe_ctlr_power_up(cam); | ||
2226 | set_bit(CF_CONFIG_NEEDED, &cam->flags); | ||
2227 | if (cam->state == S_SPECREAD) | ||
2228 | cam->state = S_IDLE; /* Don't bother restarting */ | ||
2229 | else if (cam->state == S_SINGLEREAD || cam->state == S_STREAMING) | ||
2230 | ret = cafe_read_setup(cam, cam->state); | ||
2231 | return ret; | ||
2232 | } | ||
2233 | |||
2234 | #endif /* CONFIG_PM */ | ||
2179 | 2235 | ||
2180 | 2236 | ||
2181 | static struct pci_device_id cafe_ids[] = { | 2237 | static struct pci_device_id cafe_ids[] = { |
2182 | { PCI_DEVICE(0x1148, 0x4340) }, /* Temporary ID on devel board */ | ||
2183 | { PCI_DEVICE(0x11ab, 0x4100) }, /* Eventual real ID */ | 2238 | { PCI_DEVICE(0x11ab, 0x4100) }, /* Eventual real ID */ |
2184 | { PCI_DEVICE(0x11ab, 0x4102) }, /* Really eventual real ID */ | 2239 | { PCI_DEVICE(0x11ab, 0x4102) }, /* Really eventual real ID */ |
2185 | { 0, } | 2240 | { 0, } |
@@ -2192,6 +2247,10 @@ static struct pci_driver cafe_pci_driver = { | |||
2192 | .id_table = cafe_ids, | 2247 | .id_table = cafe_ids, |
2193 | .probe = cafe_pci_probe, | 2248 | .probe = cafe_pci_probe, |
2194 | .remove = cafe_pci_remove, | 2249 | .remove = cafe_pci_remove, |
2250 | #ifdef CONFIG_PM | ||
2251 | .suspend = cafe_pci_suspend, | ||
2252 | .resume = cafe_pci_resume, | ||
2253 | #endif | ||
2195 | }; | 2254 | }; |
2196 | 2255 | ||
2197 | 2256 | ||
diff --git a/drivers/media/video/cpia_pp.c b/drivers/media/video/cpia_pp.c index b12cec94f4cc..19711aaf9a3e 100644 --- a/drivers/media/video/cpia_pp.c +++ b/drivers/media/video/cpia_pp.c | |||
@@ -62,7 +62,6 @@ static int cpia_pp_close(void *privdata); | |||
62 | #define PPCPIA_PARPORT_OFF -2 | 62 | #define PPCPIA_PARPORT_OFF -2 |
63 | #define PPCPIA_PARPORT_NONE -1 | 63 | #define PPCPIA_PARPORT_NONE -1 |
64 | 64 | ||
65 | #ifdef MODULE | ||
66 | static int parport_nr[PARPORT_MAX] = {[0 ... PARPORT_MAX - 1] = PPCPIA_PARPORT_UNSPEC}; | 65 | static int parport_nr[PARPORT_MAX] = {[0 ... PARPORT_MAX - 1] = PPCPIA_PARPORT_UNSPEC}; |
67 | static char *parport[PARPORT_MAX] = {NULL,}; | 66 | static char *parport[PARPORT_MAX] = {NULL,}; |
68 | 67 | ||
@@ -72,11 +71,6 @@ MODULE_LICENSE("GPL"); | |||
72 | 71 | ||
73 | module_param_array(parport, charp, NULL, 0); | 72 | module_param_array(parport, charp, NULL, 0); |
74 | MODULE_PARM_DESC(parport, "'auto' or a list of parallel port numbers. Just like lp."); | 73 | MODULE_PARM_DESC(parport, "'auto' or a list of parallel port numbers. Just like lp."); |
75 | #else | ||
76 | static int parport_nr[PARPORT_MAX] __initdata = | ||
77 | {[0 ... PARPORT_MAX - 1] = PPCPIA_PARPORT_UNSPEC}; | ||
78 | static int parport_ptr = 0; | ||
79 | #endif | ||
80 | 74 | ||
81 | struct pp_cam_entry { | 75 | struct pp_cam_entry { |
82 | struct pardevice *pdev; | 76 | struct pardevice *pdev; |
@@ -141,7 +135,6 @@ static void cpia_pp_run_callback(struct work_struct *work) | |||
141 | cam = container_of(work, struct pp_cam_entry, cb_task); | 135 | cam = container_of(work, struct pp_cam_entry, cb_task); |
142 | cb_func = cam->cb_func; | 136 | cb_func = cam->cb_func; |
143 | cb_data = cam->cb_data; | 137 | cb_data = cam->cb_data; |
144 | work_release(work); | ||
145 | 138 | ||
146 | cb_func(cb_data); | 139 | cb_func(cb_data); |
147 | } | 140 | } |
@@ -682,7 +675,7 @@ static int cpia_pp_registerCallback(void *privdata, void (*cb)(void *cbdata), vo | |||
682 | if(cam->port->irq != PARPORT_IRQ_NONE) { | 675 | if(cam->port->irq != PARPORT_IRQ_NONE) { |
683 | cam->cb_func = cb; | 676 | cam->cb_func = cb; |
684 | cam->cb_data = cbdata; | 677 | cam->cb_data = cbdata; |
685 | INIT_WORK_NAR(&cam->cb_task, cpia_pp_run_callback); | 678 | INIT_WORK(&cam->cb_task, cpia_pp_run_callback); |
686 | } else { | 679 | } else { |
687 | retval = -1; | 680 | retval = -1; |
688 | } | 681 | } |
@@ -820,7 +813,7 @@ static struct parport_driver cpia_pp_driver = { | |||
820 | .detach = cpia_pp_detach, | 813 | .detach = cpia_pp_detach, |
821 | }; | 814 | }; |
822 | 815 | ||
823 | static int cpia_pp_init(void) | 816 | static int __init cpia_pp_init(void) |
824 | { | 817 | { |
825 | printk(KERN_INFO "%s v%d.%d.%d\n",ABOUT, | 818 | printk(KERN_INFO "%s v%d.%d.%d\n",ABOUT, |
826 | CPIA_PP_MAJ_VER,CPIA_PP_MIN_VER,CPIA_PP_PATCH_VER); | 819 | CPIA_PP_MAJ_VER,CPIA_PP_MIN_VER,CPIA_PP_PATCH_VER); |
@@ -839,8 +832,7 @@ static int cpia_pp_init(void) | |||
839 | return 0; | 832 | return 0; |
840 | } | 833 | } |
841 | 834 | ||
842 | #ifdef MODULE | 835 | static int __init cpia_init(void) |
843 | int init_module(void) | ||
844 | { | 836 | { |
845 | if (parport[0]) { | 837 | if (parport[0]) { |
846 | /* The user gave some parameters. Let's see what they were. */ | 838 | /* The user gave some parameters. Let's see what they were. */ |
@@ -867,38 +859,11 @@ int init_module(void) | |||
867 | return cpia_pp_init(); | 859 | return cpia_pp_init(); |
868 | } | 860 | } |
869 | 861 | ||
870 | void cleanup_module(void) | 862 | static void __exit cpia_cleanup(void) |
871 | { | 863 | { |
872 | parport_unregister_driver (&cpia_pp_driver); | 864 | parport_unregister_driver(&cpia_pp_driver); |
873 | return; | 865 | return; |
874 | } | 866 | } |
875 | 867 | ||
876 | #else /* !MODULE */ | 868 | module_init(cpia_init); |
877 | 869 | module_exit(cpia_cleanup); | |
878 | static int __init cpia_pp_setup(char *str) | ||
879 | { | ||
880 | int err; | ||
881 | |||
882 | if (!strncmp(str, "parport", 7)) { | ||
883 | int n = simple_strtoul(str + 7, NULL, 10); | ||
884 | if (parport_ptr < PARPORT_MAX) { | ||
885 | parport_nr[parport_ptr++] = n; | ||
886 | } else { | ||
887 | LOG("too many ports, %s ignored.\n", str); | ||
888 | } | ||
889 | } else if (!strcmp(str, "auto")) { | ||
890 | parport_nr[0] = PPCPIA_PARPORT_AUTO; | ||
891 | } else if (!strcmp(str, "none")) { | ||
892 | parport_nr[parport_ptr++] = PPCPIA_PARPORT_NONE; | ||
893 | } | ||
894 | |||
895 | err=cpia_pp_init(); | ||
896 | if (err) | ||
897 | return err; | ||
898 | |||
899 | return 1; | ||
900 | } | ||
901 | |||
902 | __setup("cpia_pp=", cpia_pp_setup); | ||
903 | |||
904 | #endif /* !MODULE */ | ||
diff --git a/drivers/media/video/cs53l32a.c b/drivers/media/video/cs53l32a.c index de87247c74ee..a73e285af730 100644 --- a/drivers/media/video/cs53l32a.c +++ b/drivers/media/video/cs53l32a.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/i2c-id.h> | 28 | #include <linux/i2c-id.h> |
29 | #include <linux/videodev.h> | 29 | #include <linux/videodev.h> |
30 | #include <media/v4l2-common.h> | 30 | #include <media/v4l2-common.h> |
31 | #include <media/v4l2-chip-ident.h> | ||
31 | 32 | ||
32 | MODULE_DESCRIPTION("i2c device driver for cs53l32a Audio ADC"); | 33 | MODULE_DESCRIPTION("i2c device driver for cs53l32a Audio ADC"); |
33 | MODULE_AUTHOR("Martin Vaughan"); | 34 | MODULE_AUTHOR("Martin Vaughan"); |
@@ -103,6 +104,9 @@ static int cs53l32a_command(struct i2c_client *client, unsigned int cmd, | |||
103 | cs53l32a_write(client, 0x05, (u8) ctrl->value); | 104 | cs53l32a_write(client, 0x05, (u8) ctrl->value); |
104 | break; | 105 | break; |
105 | 106 | ||
107 | case VIDIOC_G_CHIP_IDENT: | ||
108 | return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_CS53l32A, 0); | ||
109 | |||
106 | case VIDIOC_LOG_STATUS: | 110 | case VIDIOC_LOG_STATUS: |
107 | { | 111 | { |
108 | u8 v = cs53l32a_read(client, 0x01); | 112 | u8 v = cs53l32a_read(client, 0x01); |
diff --git a/drivers/media/video/cx2341x.c b/drivers/media/video/cx2341x.c index d60cd5ecf821..88dbdddeec42 100644 --- a/drivers/media/video/cx2341x.c +++ b/drivers/media/video/cx2341x.c | |||
@@ -51,6 +51,7 @@ const u32 cx2341x_mpeg_ctrls[] = { | |||
51 | V4L2_CID_MPEG_AUDIO_MODE_EXTENSION, | 51 | V4L2_CID_MPEG_AUDIO_MODE_EXTENSION, |
52 | V4L2_CID_MPEG_AUDIO_EMPHASIS, | 52 | V4L2_CID_MPEG_AUDIO_EMPHASIS, |
53 | V4L2_CID_MPEG_AUDIO_CRC, | 53 | V4L2_CID_MPEG_AUDIO_CRC, |
54 | V4L2_CID_MPEG_AUDIO_MUTE, | ||
54 | V4L2_CID_MPEG_VIDEO_ENCODING, | 55 | V4L2_CID_MPEG_VIDEO_ENCODING, |
55 | V4L2_CID_MPEG_VIDEO_ASPECT, | 56 | V4L2_CID_MPEG_VIDEO_ASPECT, |
56 | V4L2_CID_MPEG_VIDEO_B_FRAMES, | 57 | V4L2_CID_MPEG_VIDEO_B_FRAMES, |
@@ -60,6 +61,8 @@ const u32 cx2341x_mpeg_ctrls[] = { | |||
60 | V4L2_CID_MPEG_VIDEO_BITRATE, | 61 | V4L2_CID_MPEG_VIDEO_BITRATE, |
61 | V4L2_CID_MPEG_VIDEO_BITRATE_PEAK, | 62 | V4L2_CID_MPEG_VIDEO_BITRATE_PEAK, |
62 | V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION, | 63 | V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION, |
64 | V4L2_CID_MPEG_VIDEO_MUTE, | ||
65 | V4L2_CID_MPEG_VIDEO_MUTE_YUV, | ||
63 | V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE, | 66 | V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE, |
64 | V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER, | 67 | V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER, |
65 | V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE, | 68 | V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE, |
@@ -71,6 +74,7 @@ const u32 cx2341x_mpeg_ctrls[] = { | |||
71 | V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP, | 74 | V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP, |
72 | V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM, | 75 | V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM, |
73 | V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP, | 76 | V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP, |
77 | V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS, | ||
74 | 0 | 78 | 0 |
75 | }; | 79 | }; |
76 | 80 | ||
@@ -102,6 +106,9 @@ static int cx2341x_get_ctrl(struct cx2341x_mpeg_params *params, | |||
102 | case V4L2_CID_MPEG_AUDIO_CRC: | 106 | case V4L2_CID_MPEG_AUDIO_CRC: |
103 | ctrl->value = params->audio_crc; | 107 | ctrl->value = params->audio_crc; |
104 | break; | 108 | break; |
109 | case V4L2_CID_MPEG_AUDIO_MUTE: | ||
110 | ctrl->value = params->audio_mute; | ||
111 | break; | ||
105 | case V4L2_CID_MPEG_VIDEO_ENCODING: | 112 | case V4L2_CID_MPEG_VIDEO_ENCODING: |
106 | ctrl->value = params->video_encoding; | 113 | ctrl->value = params->video_encoding; |
107 | break; | 114 | break; |
@@ -129,6 +136,12 @@ static int cx2341x_get_ctrl(struct cx2341x_mpeg_params *params, | |||
129 | case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: | 136 | case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: |
130 | ctrl->value = params->video_temporal_decimation; | 137 | ctrl->value = params->video_temporal_decimation; |
131 | break; | 138 | break; |
139 | case V4L2_CID_MPEG_VIDEO_MUTE: | ||
140 | ctrl->value = params->video_mute; | ||
141 | break; | ||
142 | case V4L2_CID_MPEG_VIDEO_MUTE_YUV: | ||
143 | ctrl->value = params->video_mute_yuv; | ||
144 | break; | ||
132 | case V4L2_CID_MPEG_STREAM_TYPE: | 145 | case V4L2_CID_MPEG_STREAM_TYPE: |
133 | ctrl->value = params->stream_type; | 146 | ctrl->value = params->stream_type; |
134 | break; | 147 | break; |
@@ -168,6 +181,9 @@ static int cx2341x_get_ctrl(struct cx2341x_mpeg_params *params, | |||
168 | case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM: | 181 | case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM: |
169 | ctrl->value = params->video_chroma_median_filter_bottom; | 182 | ctrl->value = params->video_chroma_median_filter_bottom; |
170 | break; | 183 | break; |
184 | case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS: | ||
185 | ctrl->value = params->stream_insert_nav_packets; | ||
186 | break; | ||
171 | default: | 187 | default: |
172 | return -EINVAL; | 188 | return -EINVAL; |
173 | } | 189 | } |
@@ -201,6 +217,9 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, | |||
201 | case V4L2_CID_MPEG_AUDIO_CRC: | 217 | case V4L2_CID_MPEG_AUDIO_CRC: |
202 | params->audio_crc = ctrl->value; | 218 | params->audio_crc = ctrl->value; |
203 | break; | 219 | break; |
220 | case V4L2_CID_MPEG_AUDIO_MUTE: | ||
221 | params->audio_mute = ctrl->value; | ||
222 | break; | ||
204 | case V4L2_CID_MPEG_VIDEO_ASPECT: | 223 | case V4L2_CID_MPEG_VIDEO_ASPECT: |
205 | params->video_aspect = ctrl->value; | 224 | params->video_aspect = ctrl->value; |
206 | break; | 225 | break; |
@@ -243,6 +262,12 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, | |||
243 | case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: | 262 | case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: |
244 | params->video_temporal_decimation = ctrl->value; | 263 | params->video_temporal_decimation = ctrl->value; |
245 | break; | 264 | break; |
265 | case V4L2_CID_MPEG_VIDEO_MUTE: | ||
266 | params->video_mute = (ctrl->value != 0); | ||
267 | break; | ||
268 | case V4L2_CID_MPEG_VIDEO_MUTE_YUV: | ||
269 | params->video_mute_yuv = ctrl->value; | ||
270 | break; | ||
246 | case V4L2_CID_MPEG_STREAM_TYPE: | 271 | case V4L2_CID_MPEG_STREAM_TYPE: |
247 | params->stream_type = ctrl->value; | 272 | params->stream_type = ctrl->value; |
248 | params->video_encoding = | 273 | params->video_encoding = |
@@ -290,6 +315,9 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, | |||
290 | case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM: | 315 | case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM: |
291 | params->video_chroma_median_filter_bottom = ctrl->value; | 316 | params->video_chroma_median_filter_bottom = ctrl->value; |
292 | break; | 317 | break; |
318 | case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS: | ||
319 | params->stream_insert_nav_packets = ctrl->value; | ||
320 | break; | ||
293 | default: | 321 | default: |
294 | return -EINVAL; | 322 | return -EINVAL; |
295 | } | 323 | } |
@@ -336,6 +364,9 @@ static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 ma | |||
336 | case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM: | 364 | case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM: |
337 | name = "Median Chroma Filter Minimum"; | 365 | name = "Median Chroma Filter Minimum"; |
338 | break; | 366 | break; |
367 | case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS: | ||
368 | name = "Insert Navigation Packets"; | ||
369 | break; | ||
339 | 370 | ||
340 | default: | 371 | default: |
341 | return v4l2_ctrl_query_fill(qctrl, min, max, step, def); | 372 | return v4l2_ctrl_query_fill(qctrl, min, max, step, def); |
@@ -350,6 +381,12 @@ static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 ma | |||
350 | min = 0; | 381 | min = 0; |
351 | step = 1; | 382 | step = 1; |
352 | break; | 383 | break; |
384 | case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS: | ||
385 | qctrl->type = V4L2_CTRL_TYPE_BOOLEAN; | ||
386 | min = 0; | ||
387 | max = 1; | ||
388 | step = 1; | ||
389 | break; | ||
353 | default: | 390 | default: |
354 | qctrl->type = V4L2_CTRL_TYPE_INTEGER; | 391 | qctrl->type = V4L2_CTRL_TYPE_INTEGER; |
355 | break; | 392 | break; |
@@ -505,6 +542,9 @@ int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, struct v4l2_queryctrl | |||
505 | qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; | 542 | qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; |
506 | return 0; | 543 | return 0; |
507 | 544 | ||
545 | case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS: | ||
546 | return cx2341x_ctrl_query_fill(qctrl, 0, 1, 1, 0); | ||
547 | |||
508 | default: | 548 | default: |
509 | return v4l2_ctrl_query_fill_std(qctrl); | 549 | return v4l2_ctrl_query_fill_std(qctrl); |
510 | 550 | ||
@@ -656,6 +696,7 @@ void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p) | |||
656 | /* stream */ | 696 | /* stream */ |
657 | .stream_type = V4L2_MPEG_STREAM_TYPE_MPEG2_PS, | 697 | .stream_type = V4L2_MPEG_STREAM_TYPE_MPEG2_PS, |
658 | .stream_vbi_fmt = V4L2_MPEG_STREAM_VBI_FMT_NONE, | 698 | .stream_vbi_fmt = V4L2_MPEG_STREAM_VBI_FMT_NONE, |
699 | .stream_insert_nav_packets = 0, | ||
659 | 700 | ||
660 | /* audio */ | 701 | /* audio */ |
661 | .audio_sampling_freq = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000, | 702 | .audio_sampling_freq = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000, |
@@ -665,6 +706,7 @@ void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p) | |||
665 | .audio_mode_extension = V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4, | 706 | .audio_mode_extension = V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4, |
666 | .audio_emphasis = V4L2_MPEG_AUDIO_EMPHASIS_NONE, | 707 | .audio_emphasis = V4L2_MPEG_AUDIO_EMPHASIS_NONE, |
667 | .audio_crc = V4L2_MPEG_AUDIO_CRC_NONE, | 708 | .audio_crc = V4L2_MPEG_AUDIO_CRC_NONE, |
709 | .audio_mute = 0, | ||
668 | 710 | ||
669 | /* video */ | 711 | /* video */ |
670 | .video_encoding = V4L2_MPEG_VIDEO_ENCODING_MPEG_2, | 712 | .video_encoding = V4L2_MPEG_VIDEO_ENCODING_MPEG_2, |
@@ -676,6 +718,8 @@ void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p) | |||
676 | .video_bitrate = 6000000, | 718 | .video_bitrate = 6000000, |
677 | .video_bitrate_peak = 8000000, | 719 | .video_bitrate_peak = 8000000, |
678 | .video_temporal_decimation = 0, | 720 | .video_temporal_decimation = 0, |
721 | .video_mute = 0, | ||
722 | .video_mute_yuv = 0x008080, /* YCbCr value for black */ | ||
679 | 723 | ||
680 | /* encoding filters */ | 724 | /* encoding filters */ |
681 | .video_spatial_filter_mode = V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL, | 725 | .video_spatial_filter_mode = V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL, |
@@ -779,6 +823,10 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func, | |||
779 | err = cx2341x_api(priv, func, CX2341X_ENC_SET_AUDIO_PROPERTIES, 1, new->audio_properties); | 823 | err = cx2341x_api(priv, func, CX2341X_ENC_SET_AUDIO_PROPERTIES, 1, new->audio_properties); |
780 | if (err) return err; | 824 | if (err) return err; |
781 | } | 825 | } |
826 | if (old == NULL || old->audio_mute != new->audio_mute) { | ||
827 | err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_AUDIO, 1, new->audio_mute); | ||
828 | if (err) return err; | ||
829 | } | ||
782 | if (old == NULL || old->video_bitrate_mode != new->video_bitrate_mode || | 830 | if (old == NULL || old->video_bitrate_mode != new->video_bitrate_mode || |
783 | old->video_bitrate != new->video_bitrate || | 831 | old->video_bitrate != new->video_bitrate || |
784 | old->video_bitrate_peak != new->video_bitrate_peak) { | 832 | old->video_bitrate_peak != new->video_bitrate_peak) { |
@@ -826,6 +874,15 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func, | |||
826 | new->video_temporal_decimation); | 874 | new->video_temporal_decimation); |
827 | if (err) return err; | 875 | if (err) return err; |
828 | } | 876 | } |
877 | if (old == NULL || old->video_mute != new->video_mute || | ||
878 | (new->video_mute && old->video_mute_yuv != new->video_mute_yuv)) { | ||
879 | err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_VIDEO, 1, new->video_mute | (new->video_mute_yuv << 8)); | ||
880 | if (err) return err; | ||
881 | } | ||
882 | if (old == NULL || old->stream_insert_nav_packets != new->stream_insert_nav_packets) { | ||
883 | err = cx2341x_api(priv, func, CX2341X_ENC_MISC, 2, 7, new->stream_insert_nav_packets); | ||
884 | if (err) return err; | ||
885 | } | ||
829 | return 0; | 886 | return 0; |
830 | } | 887 | } |
831 | 888 | ||
@@ -854,18 +911,22 @@ void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix) | |||
854 | int temporal = p->video_temporal_filter; | 911 | int temporal = p->video_temporal_filter; |
855 | 912 | ||
856 | /* Stream */ | 913 | /* Stream */ |
857 | printk(KERN_INFO "%s: Stream: %s\n", | 914 | printk(KERN_INFO "%s: Stream: %s", |
858 | prefix, | 915 | prefix, |
859 | cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_TYPE)); | 916 | cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_TYPE)); |
917 | if (p->stream_insert_nav_packets) | ||
918 | printk(" (with navigation packets)"); | ||
919 | printk("\n"); | ||
860 | printk(KERN_INFO "%s: VBI Format: %s\n", | 920 | printk(KERN_INFO "%s: VBI Format: %s\n", |
861 | prefix, | 921 | prefix, |
862 | cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_VBI_FMT)); | 922 | cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_VBI_FMT)); |
863 | 923 | ||
864 | /* Video */ | 924 | /* Video */ |
865 | printk(KERN_INFO "%s: Video: %dx%d, %d fps\n", | 925 | printk(KERN_INFO "%s: Video: %dx%d, %d fps%s\n", |
866 | prefix, | 926 | prefix, |
867 | p->width / (is_mpeg1 ? 2 : 1), p->height / (is_mpeg1 ? 2 : 1), | 927 | p->width / (is_mpeg1 ? 2 : 1), p->height / (is_mpeg1 ? 2 : 1), |
868 | p->is_50hz ? 25 : 30); | 928 | p->is_50hz ? 25 : 30, |
929 | (p->video_mute) ? " (muted)" : ""); | ||
869 | printk(KERN_INFO "%s: Video: %s, %s, %s, %d", | 930 | printk(KERN_INFO "%s: Video: %s, %s, %s, %d", |
870 | prefix, | 931 | prefix, |
871 | cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ENCODING), | 932 | cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ENCODING), |
@@ -886,12 +947,13 @@ void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix) | |||
886 | } | 947 | } |
887 | 948 | ||
888 | /* Audio */ | 949 | /* Audio */ |
889 | printk(KERN_INFO "%s: Audio: %s, %s, %s, %s", | 950 | printk(KERN_INFO "%s: Audio: %s, %s, %s, %s%s", |
890 | prefix, | 951 | prefix, |
891 | cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ), | 952 | cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ), |
892 | cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_ENCODING), | 953 | cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_ENCODING), |
893 | cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_L2_BITRATE), | 954 | cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_L2_BITRATE), |
894 | cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE)); | 955 | cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE), |
956 | p->audio_mute ? " (muted)" : ""); | ||
895 | if (p->audio_mode == V4L2_MPEG_AUDIO_MODE_JOINT_STEREO) { | 957 | if (p->audio_mode == V4L2_MPEG_AUDIO_MODE_JOINT_STEREO) { |
896 | printk(", %s", | 958 | printk(", %s", |
897 | cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE_EXTENSION)); | 959 | cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE_EXTENSION)); |
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index 774d2536555b..1757a588970f 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/videodev2.h> | 35 | #include <linux/videodev2.h> |
36 | #include <linux/i2c.h> | 36 | #include <linux/i2c.h> |
37 | #include <media/v4l2-common.h> | 37 | #include <media/v4l2-common.h> |
38 | #include <media/v4l2-chip-ident.h> | ||
38 | #include <media/cx25840.h> | 39 | #include <media/cx25840.h> |
39 | 40 | ||
40 | #include "cx25840-core.h" | 41 | #include "cx25840-core.h" |
@@ -827,9 +828,8 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, | |||
827 | cx25840_initialize(client, 0); | 828 | cx25840_initialize(client, 0); |
828 | break; | 829 | break; |
829 | 830 | ||
830 | case VIDIOC_INT_G_CHIP_IDENT: | 831 | case VIDIOC_G_CHIP_IDENT: |
831 | *(enum v4l2_chip_ident *)arg = state->id; | 832 | return v4l2_chip_ident_i2c_client(client, arg, state->id, state->rev); |
832 | break; | ||
833 | 833 | ||
834 | default: | 834 | default: |
835 | return -EINVAL; | 835 | return -EINVAL; |
@@ -847,7 +847,7 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address, | |||
847 | { | 847 | { |
848 | struct i2c_client *client; | 848 | struct i2c_client *client; |
849 | struct cx25840_state *state; | 849 | struct cx25840_state *state; |
850 | enum v4l2_chip_ident id; | 850 | u32 id; |
851 | u16 device_id; | 851 | u16 device_id; |
852 | 852 | ||
853 | /* Check if the adapter supports the needed features | 853 | /* Check if the adapter supports the needed features |
@@ -902,6 +902,7 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address, | |||
902 | state->audmode = V4L2_TUNER_MODE_LANG1; | 902 | state->audmode = V4L2_TUNER_MODE_LANG1; |
903 | state->vbi_line_offset = 8; | 903 | state->vbi_line_offset = 8; |
904 | state->id = id; | 904 | state->id = id; |
905 | state->rev = device_id; | ||
905 | 906 | ||
906 | i2c_attach_client(client); | 907 | i2c_attach_client(client); |
907 | 908 | ||
diff --git a/drivers/media/video/cx25840/cx25840-core.h b/drivers/media/video/cx25840/cx25840-core.h index 28049064dd7d..f4b56d2fd6b6 100644 --- a/drivers/media/video/cx25840/cx25840-core.h +++ b/drivers/media/video/cx25840/cx25840-core.h | |||
@@ -43,7 +43,8 @@ struct cx25840_state { | |||
43 | u32 audclk_freq; | 43 | u32 audclk_freq; |
44 | int audmode; | 44 | int audmode; |
45 | int vbi_line_offset; | 45 | int vbi_line_offset; |
46 | enum v4l2_chip_ident id; | 46 | u32 id; |
47 | u32 rev; | ||
47 | int is_cx25836; | 48 | int is_cx25836; |
48 | }; | 49 | }; |
49 | 50 | ||
diff --git a/drivers/media/video/cx25840/cx25840-firmware.c b/drivers/media/video/cx25840/cx25840-firmware.c index 0e86b9d033ac..e852024a5ea3 100644 --- a/drivers/media/video/cx25840/cx25840-firmware.c +++ b/drivers/media/video/cx25840/cx25840-firmware.c | |||
@@ -17,7 +17,6 @@ | |||
17 | 17 | ||
18 | #include <linux/module.h> | 18 | #include <linux/module.h> |
19 | #include <linux/i2c.h> | 19 | #include <linux/i2c.h> |
20 | #include <linux/i2c-algo-bit.h> | ||
21 | #include <linux/firmware.h> | 20 | #include <linux/firmware.h> |
22 | #include <media/v4l2-common.h> | 21 | #include <media/v4l2-common.h> |
23 | #include <media/cx25840.h> | 22 | #include <media/cx25840.h> |
diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig index b2a66ba625f9..0f9d96963618 100644 --- a/drivers/media/video/cx88/Kconfig +++ b/drivers/media/video/cx88/Kconfig | |||
@@ -53,7 +53,6 @@ config VIDEO_CX88_DVB | |||
53 | select DVB_OR51132 if !DVB_FE_CUSTOMISE | 53 | select DVB_OR51132 if !DVB_FE_CUSTOMISE |
54 | select DVB_CX22702 if !DVB_FE_CUSTOMISE | 54 | select DVB_CX22702 if !DVB_FE_CUSTOMISE |
55 | select DVB_LGDT330X if !DVB_FE_CUSTOMISE | 55 | select DVB_LGDT330X if !DVB_FE_CUSTOMISE |
56 | select DVB_TUNER_LGH06XF if !DVB_FE_CUSTOMISE | ||
57 | select DVB_NXT200X if !DVB_FE_CUSTOMISE | 56 | select DVB_NXT200X if !DVB_FE_CUSTOMISE |
58 | select DVB_CX24123 if !DVB_FE_CUSTOMISE | 57 | select DVB_CX24123 if !DVB_FE_CUSTOMISE |
59 | select DVB_ISL6421 if !DVB_FE_CUSTOMISE | 58 | select DVB_ISL6421 if !DVB_FE_CUSTOMISE |
diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c index e4355fdc3b6d..3956c257556c 100644 --- a/drivers/media/video/cx88/cx88-alsa.c +++ b/drivers/media/video/cx88/cx88-alsa.c | |||
@@ -232,7 +232,8 @@ static void cx8801_aud_irq(snd_cx88_card_t *chip) | |||
232 | cx_write(MO_AUD_INTSTAT, status); | 232 | cx_write(MO_AUD_INTSTAT, status); |
233 | if (debug > 1 || (status & mask & ~0xff)) | 233 | if (debug > 1 || (status & mask & ~0xff)) |
234 | cx88_print_irqbits(core->name, "irq aud", | 234 | cx88_print_irqbits(core->name, "irq aud", |
235 | cx88_aud_irqs, status, mask); | 235 | cx88_aud_irqs, ARRAY_SIZE(cx88_aud_irqs), |
236 | status, mask); | ||
236 | /* risc op code error */ | 237 | /* risc op code error */ |
237 | if (status & (1 << 16)) { | 238 | if (status & (1 << 16)) { |
238 | printk(KERN_WARNING "%s/0: audio risc op code error\n",core->name); | 239 | printk(KERN_WARNING "%s/0: audio risc op code error\n",core->name); |
@@ -413,11 +414,9 @@ static int snd_cx88_hw_params(struct snd_pcm_substream * substream, | |||
413 | 414 | ||
414 | dprintk(1,"Setting buffer\n"); | 415 | dprintk(1,"Setting buffer\n"); |
415 | 416 | ||
416 | buf = kmalloc(sizeof(*buf),GFP_KERNEL); | 417 | buf = kzalloc(sizeof(*buf),GFP_KERNEL); |
417 | if (NULL == buf) | 418 | if (NULL == buf) |
418 | return -ENOMEM; | 419 | return -ENOMEM; |
419 | memset(buf,0,sizeof(*buf)); | ||
420 | |||
421 | 420 | ||
422 | buf->vb.memory = V4L2_MEMORY_MMAP; | 421 | buf->vb.memory = V4L2_MEMORY_MMAP; |
423 | buf->vb.width = chip->period_size; | 422 | buf->vb.width = chip->period_size; |
@@ -682,7 +681,7 @@ static int __devinit snd_cx88_create(struct snd_card *card, | |||
682 | return err; | 681 | return err; |
683 | } | 682 | } |
684 | 683 | ||
685 | if (!pci_dma_supported(pci,0xffffffff)) { | 684 | if (!pci_dma_supported(pci,DMA_32BIT_MASK)) { |
686 | dprintk(0, "%s/1: Oops: no 32bit PCI DMA ???\n",core->name); | 685 | dprintk(0, "%s/1: Oops: no 32bit PCI DMA ???\n",core->name); |
687 | err = -EIO; | 686 | err = -EIO; |
688 | cx88_core_put(core,pci); | 687 | cx88_core_put(core,pci); |
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index 65e9d8096b74..e61102dc8ad7 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c | |||
@@ -885,6 +885,12 @@ struct cx88_board cx88_boards[] = { | |||
885 | .input = {{ | 885 | .input = {{ |
886 | .type = CX88_VMUX_DVB, | 886 | .type = CX88_VMUX_DVB, |
887 | .vmux = 0, | 887 | .vmux = 0, |
888 | },{ | ||
889 | .type = CX88_VMUX_COMPOSITE1, | ||
890 | .vmux = 1, | ||
891 | },{ | ||
892 | .type = CX88_VMUX_SVIDEO, | ||
893 | .vmux = 2, | ||
888 | }}, | 894 | }}, |
889 | .mpeg = CX88_MPEG_DVB, | 895 | .mpeg = CX88_MPEG_DVB, |
890 | }, | 896 | }, |
@@ -1537,10 +1543,10 @@ struct cx88_subid cx88_subids[] = { | |||
1537 | },{ | 1543 | },{ |
1538 | .subvendor = 0x17de, | 1544 | .subvendor = 0x17de, |
1539 | .subdevice = 0x0840, | 1545 | .subdevice = 0x0840, |
1540 | .card = CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT, | 1546 | .card = CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT, |
1541 | },{ | 1547 | },{ |
1542 | .subvendor = 0x1421, | 1548 | .subvendor = 0x1421, |
1543 | .subdevice = 0x0305, | 1549 | .subdevice = 0x0305, |
1544 | .card = CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT, | 1550 | .card = CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT, |
1545 | },{ | 1551 | },{ |
1546 | .subvendor = 0x18ac, | 1552 | .subvendor = 0x18ac, |
@@ -1631,6 +1637,10 @@ struct cx88_subid cx88_subids[] = { | |||
1631 | .subvendor = 0x0070, | 1637 | .subvendor = 0x0070, |
1632 | .subdevice = 0x1402, | 1638 | .subdevice = 0x1402, |
1633 | .card = CX88_BOARD_HAUPPAUGE_HVR3000, | 1639 | .card = CX88_BOARD_HAUPPAUGE_HVR3000, |
1640 | },{ | ||
1641 | .subvendor = 0x1421, | ||
1642 | .subdevice = 0x0341, /* ADS Tech InstantTV DVB-S */ | ||
1643 | .card = CX88_BOARD_KWORLD_DVBS_100, | ||
1634 | }, | 1644 | }, |
1635 | }; | 1645 | }; |
1636 | const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids); | 1646 | const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids); |
@@ -1786,7 +1796,7 @@ static void dvico_fusionhdtv_hybrid_init(struct cx88_core *core) | |||
1786 | { 0x03, 0x0C }, | 1796 | { 0x03, 0x0C }, |
1787 | }; | 1797 | }; |
1788 | 1798 | ||
1789 | for (i = 0; i < 13; i++) { | 1799 | for (i = 0; i < ARRAY_SIZE(init_bufs); i++) { |
1790 | msg.buf = init_bufs[i]; | 1800 | msg.buf = init_bufs[i]; |
1791 | msg.len = (i != 12 ? 5 : 2); | 1801 | msg.len = (i != 12 ? 5 : 2); |
1792 | err = i2c_transfer(&core->i2c_adap, &msg, 1); | 1802 | err = i2c_transfer(&core->i2c_adap, &msg, 1); |
@@ -1913,12 +1923,21 @@ void cx88_card_setup(struct cx88_core *core) | |||
1913 | if (0 == core->i2c_rc) { | 1923 | if (0 == core->i2c_rc) { |
1914 | /* enable tuner */ | 1924 | /* enable tuner */ |
1915 | int i; | 1925 | int i; |
1916 | static const u8 buffer [] = { 0x10,0x12,0x13,0x04,0x16,0x00,0x14,0x04,0x017,0x00 }; | 1926 | static const u8 buffer [][2] = { |
1927 | {0x10,0x12}, | ||
1928 | {0x13,0x04}, | ||
1929 | {0x16,0x00}, | ||
1930 | {0x14,0x04}, | ||
1931 | {0x17,0x00} | ||
1932 | }; | ||
1917 | core->i2c_client.addr = 0x0a; | 1933 | core->i2c_client.addr = 0x0a; |
1918 | 1934 | ||
1919 | for (i = 0; i < 5; i++) | 1935 | for (i = 0; i < ARRAY_SIZE(buffer); i++) |
1920 | if (2 != i2c_master_send(&core->i2c_client,&buffer[i*2],2)) | 1936 | if (2 != i2c_master_send(&core->i2c_client, |
1921 | printk(KERN_WARNING "%s: Unable to enable tuner(%i).\n", | 1937 | buffer[i],2)) |
1938 | printk(KERN_WARNING | ||
1939 | "%s: Unable to enable " | ||
1940 | "tuner(%i).\n", | ||
1922 | core->name, i); | 1941 | core->name, i); |
1923 | } | 1942 | } |
1924 | break; | 1943 | break; |
diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index d86813be56de..f31ec96924b9 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c | |||
@@ -489,12 +489,12 @@ static char *cx88_pci_irqs[32] = { | |||
489 | }; | 489 | }; |
490 | 490 | ||
491 | void cx88_print_irqbits(char *name, char *tag, char **strings, | 491 | void cx88_print_irqbits(char *name, char *tag, char **strings, |
492 | u32 bits, u32 mask) | 492 | int len, u32 bits, u32 mask) |
493 | { | 493 | { |
494 | unsigned int i; | 494 | unsigned int i; |
495 | 495 | ||
496 | printk(KERN_DEBUG "%s: %s [0x%x]", name, tag, bits); | 496 | printk(KERN_DEBUG "%s: %s [0x%x]", name, tag, bits); |
497 | for (i = 0; i < 32; i++) { | 497 | for (i = 0; i < len; i++) { |
498 | if (!(bits & (1 << i))) | 498 | if (!(bits & (1 << i))) |
499 | continue; | 499 | continue; |
500 | if (strings[i]) | 500 | if (strings[i]) |
@@ -520,8 +520,8 @@ int cx88_core_irq(struct cx88_core *core, u32 status) | |||
520 | } | 520 | } |
521 | if (!handled) | 521 | if (!handled) |
522 | cx88_print_irqbits(core->name, "irq pci", | 522 | cx88_print_irqbits(core->name, "irq pci", |
523 | cx88_pci_irqs, status, | 523 | cx88_pci_irqs, ARRAY_SIZE(cx88_pci_irqs), |
524 | core->pci_irqmask); | 524 | status, core->pci_irqmask); |
525 | return handled; | 525 | return handled; |
526 | } | 526 | } |
527 | 527 | ||
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index 4f5560285770..dbfe4dc9cf8c 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c | |||
@@ -42,7 +42,6 @@ | |||
42 | #include "cx22702.h" | 42 | #include "cx22702.h" |
43 | #include "or51132.h" | 43 | #include "or51132.h" |
44 | #include "lgdt330x.h" | 44 | #include "lgdt330x.h" |
45 | #include "lgh06xf.h" | ||
46 | #include "nxt200x.h" | 45 | #include "nxt200x.h" |
47 | #include "cx24123.h" | 46 | #include "cx24123.h" |
48 | #include "isl6421.h" | 47 | #include "isl6421.h" |
@@ -476,6 +475,8 @@ static int dvb_register(struct cx8802_dev *dev) | |||
476 | case CX88_BOARD_WINFAST_DTV2000H: | 475 | case CX88_BOARD_WINFAST_DTV2000H: |
477 | case CX88_BOARD_HAUPPAUGE_HVR1100: | 476 | case CX88_BOARD_HAUPPAUGE_HVR1100: |
478 | case CX88_BOARD_HAUPPAUGE_HVR1100LP: | 477 | case CX88_BOARD_HAUPPAUGE_HVR1100LP: |
478 | case CX88_BOARD_HAUPPAUGE_HVR1300: | ||
479 | case CX88_BOARD_HAUPPAUGE_HVR3000: | ||
479 | dev->dvb.frontend = dvb_attach(cx22702_attach, | 480 | dev->dvb.frontend = dvb_attach(cx22702_attach, |
480 | &hauppauge_hvr_config, | 481 | &hauppauge_hvr_config, |
481 | &dev->core->i2c_adap); | 482 | &dev->core->i2c_adap); |
@@ -631,8 +632,9 @@ static int dvb_register(struct cx8802_dev *dev) | |||
631 | &fusionhdtv_5_gold, | 632 | &fusionhdtv_5_gold, |
632 | &dev->core->i2c_adap); | 633 | &dev->core->i2c_adap); |
633 | if (dev->dvb.frontend != NULL) { | 634 | if (dev->dvb.frontend != NULL) { |
634 | dvb_attach(lgh06xf_attach, dev->dvb.frontend, | 635 | dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, |
635 | &dev->core->i2c_adap); | 636 | &dev->core->i2c_adap, |
637 | &dvb_pll_lg_tdvs_h06xf); | ||
636 | } | 638 | } |
637 | } | 639 | } |
638 | break; | 640 | break; |
@@ -650,8 +652,9 @@ static int dvb_register(struct cx8802_dev *dev) | |||
650 | &pchdtv_hd5500, | 652 | &pchdtv_hd5500, |
651 | &dev->core->i2c_adap); | 653 | &dev->core->i2c_adap); |
652 | if (dev->dvb.frontend != NULL) { | 654 | if (dev->dvb.frontend != NULL) { |
653 | dvb_attach(lgh06xf_attach, dev->dvb.frontend, | 655 | dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, |
654 | &dev->core->i2c_adap); | 656 | &dev->core->i2c_adap, |
657 | &dvb_pll_lg_tdvs_h06xf); | ||
655 | } | 658 | } |
656 | } | 659 | } |
657 | break; | 660 | break; |
@@ -692,24 +695,6 @@ static int dvb_register(struct cx8802_dev *dev) | |||
692 | dev->dvb.frontend->ops.set_voltage = geniatech_dvbs_set_voltage; | 695 | dev->dvb.frontend->ops.set_voltage = geniatech_dvbs_set_voltage; |
693 | } | 696 | } |
694 | break; | 697 | break; |
695 | case CX88_BOARD_HAUPPAUGE_HVR1300: | ||
696 | dev->dvb.frontend = dvb_attach(cx22702_attach, | ||
697 | &hauppauge_hvr_config, | ||
698 | &dev->core->i2c_adap); | ||
699 | if (dev->dvb.frontend != NULL) { | ||
700 | dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, | ||
701 | &dev->core->i2c_adap, &dvb_pll_fmd1216me); | ||
702 | } | ||
703 | break; | ||
704 | case CX88_BOARD_HAUPPAUGE_HVR3000: | ||
705 | dev->dvb.frontend = dvb_attach(cx22702_attach, | ||
706 | &hauppauge_hvr_config, | ||
707 | &dev->core->i2c_adap); | ||
708 | if (dev->dvb.frontend != NULL) { | ||
709 | dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, | ||
710 | &dev->core->i2c_adap, &dvb_pll_fmd1216me); | ||
711 | } | ||
712 | break; | ||
713 | default: | 698 | default: |
714 | printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n", | 699 | printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n", |
715 | dev->core->name); | 700 | dev->core->name); |
diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c index 9830d5c43921..7919a1f9da06 100644 --- a/drivers/media/video/cx88/cx88-i2c.c +++ b/drivers/media/video/cx88/cx88-i2c.c | |||
@@ -1,3 +1,4 @@ | |||
1 | |||
1 | /* | 2 | /* |
2 | 3 | ||
3 | cx88-i2c.c -- all the i2c code is here | 4 | cx88-i2c.c -- all the i2c code is here |
@@ -195,7 +196,7 @@ static void do_i2c_scan(char *name, struct i2c_client *c) | |||
195 | unsigned char buf; | 196 | unsigned char buf; |
196 | int i,rc; | 197 | int i,rc; |
197 | 198 | ||
198 | for (i = 0; i < 128; i++) { | 199 | for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) { |
199 | c->addr = i; | 200 | c->addr = i; |
200 | rc = i2c_master_recv(c,&buf,0); | 201 | rc = i2c_master_recv(c,&buf,0); |
201 | if (rc < 0) | 202 | if (rc < 0) |
diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index 1fe1a833c7c7..b2eb32e01aee 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c | |||
@@ -49,6 +49,27 @@ MODULE_PARM_DESC(debug,"enable debug messages [mpeg]"); | |||
49 | #define mpeg_dbg(level,fmt, arg...) if (debug >= level) \ | 49 | #define mpeg_dbg(level,fmt, arg...) if (debug >= level) \ |
50 | printk(KERN_DEBUG "%s/2-mpeg: " fmt, core->name, ## arg) | 50 | printk(KERN_DEBUG "%s/2-mpeg: " fmt, core->name, ## arg) |
51 | 51 | ||
52 | #if defined(CONFIG_MODULES) && defined(MODULE) | ||
53 | static void request_module_async(struct work_struct *work) | ||
54 | { | ||
55 | struct cx8802_dev *dev=container_of(work, struct cx8802_dev, request_module_wk); | ||
56 | |||
57 | if (cx88_boards[dev->core->board].mpeg & CX88_MPEG_DVB) | ||
58 | request_module("cx88-dvb"); | ||
59 | if (cx88_boards[dev->core->board].mpeg & CX88_MPEG_BLACKBIRD) | ||
60 | request_module("cx88-blackbird"); | ||
61 | } | ||
62 | |||
63 | static void request_modules(struct cx8802_dev *dev) | ||
64 | { | ||
65 | INIT_WORK(&dev->request_module_wk, request_module_async); | ||
66 | schedule_work(&dev->request_module_wk); | ||
67 | } | ||
68 | #else | ||
69 | #define request_modules(dev) | ||
70 | #endif /* CONFIG_MODULES */ | ||
71 | |||
72 | |||
52 | static LIST_HEAD(cx8802_devlist); | 73 | static LIST_HEAD(cx8802_devlist); |
53 | /* ------------------------------------------------------------------ */ | 74 | /* ------------------------------------------------------------------ */ |
54 | 75 | ||
@@ -345,7 +366,8 @@ static void cx8802_mpeg_irq(struct cx8802_dev *dev) | |||
345 | 366 | ||
346 | if (debug || (status & mask & ~0xff)) | 367 | if (debug || (status & mask & ~0xff)) |
347 | cx88_print_irqbits(core->name, "irq mpeg ", | 368 | cx88_print_irqbits(core->name, "irq mpeg ", |
348 | cx88_mpeg_irqs, status, mask); | 369 | cx88_mpeg_irqs, ARRAY_SIZE(cx88_mpeg_irqs), |
370 | status, mask); | ||
349 | 371 | ||
350 | /* risc op code error */ | 372 | /* risc op code error */ |
351 | if (status & (1 << 16)) { | 373 | if (status & (1 << 16)) { |
@@ -427,7 +449,7 @@ int cx8802_init_common(struct cx8802_dev *dev) | |||
427 | if (pci_enable_device(dev->pci)) | 449 | if (pci_enable_device(dev->pci)) |
428 | return -EIO; | 450 | return -EIO; |
429 | pci_set_master(dev->pci); | 451 | pci_set_master(dev->pci); |
430 | if (!pci_dma_supported(dev->pci,0xffffffff)) { | 452 | if (!pci_dma_supported(dev->pci,DMA_32BIT_MASK)) { |
431 | printk("%s/2: Oops: no 32bit PCI DMA ???\n",dev->core->name); | 453 | printk("%s/2: Oops: no 32bit PCI DMA ???\n",dev->core->name); |
432 | return -EIO; | 454 | return -EIO; |
433 | } | 455 | } |
@@ -778,6 +800,9 @@ static int __devinit cx8802_probe(struct pci_dev *pci_dev, | |||
778 | 800 | ||
779 | /* Maintain a reference so cx88-video can query the 8802 device. */ | 801 | /* Maintain a reference so cx88-video can query the 8802 device. */ |
780 | core->dvbdev = dev; | 802 | core->dvbdev = dev; |
803 | |||
804 | /* now autoload cx88-dvb or cx88-blackbird */ | ||
805 | request_modules(dev); | ||
781 | return 0; | 806 | return 0; |
782 | 807 | ||
783 | fail_free: | 808 | fail_free: |
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index bdfe2af70124..fbce1d50578b 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c | |||
@@ -1555,7 +1555,8 @@ static void cx8800_vid_irq(struct cx8800_dev *dev) | |||
1555 | cx_write(MO_VID_INTSTAT, status); | 1555 | cx_write(MO_VID_INTSTAT, status); |
1556 | if (irq_debug || (status & mask & ~0xff)) | 1556 | if (irq_debug || (status & mask & ~0xff)) |
1557 | cx88_print_irqbits(core->name, "irq vid", | 1557 | cx88_print_irqbits(core->name, "irq vid", |
1558 | cx88_vid_irqs, status, mask); | 1558 | cx88_vid_irqs, ARRAY_SIZE(cx88_vid_irqs), |
1559 | status, mask); | ||
1559 | 1560 | ||
1560 | /* risc op code error */ | 1561 | /* risc op code error */ |
1561 | if (status & (1 << 16)) { | 1562 | if (status & (1 << 16)) { |
@@ -1778,7 +1779,7 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, | |||
1778 | dev->pci_lat,(unsigned long long)pci_resource_start(pci_dev,0)); | 1779 | dev->pci_lat,(unsigned long long)pci_resource_start(pci_dev,0)); |
1779 | 1780 | ||
1780 | pci_set_master(pci_dev); | 1781 | pci_set_master(pci_dev); |
1781 | if (!pci_dma_supported(pci_dev,0xffffffff)) { | 1782 | if (!pci_dma_supported(pci_dev,DMA_32BIT_MASK)) { |
1782 | printk("%s/0: Oops: no 32bit PCI DMA ???\n",core->name); | 1783 | printk("%s/0: Oops: no 32bit PCI DMA ???\n",core->name); |
1783 | err = -EIO; | 1784 | err = -EIO; |
1784 | goto fail_core; | 1785 | goto fail_core; |
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index a4f7befda5b0..738d4f20c580 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h | |||
@@ -481,6 +481,8 @@ struct cx8802_dev { | |||
481 | 481 | ||
482 | /* List of attached drivers */ | 482 | /* List of attached drivers */ |
483 | struct cx8802_driver drvlist; | 483 | struct cx8802_driver drvlist; |
484 | struct work_struct request_module_wk; | ||
485 | |||
484 | }; | 486 | }; |
485 | 487 | ||
486 | /* ----------------------------------------------------------- */ | 488 | /* ----------------------------------------------------------- */ |
@@ -510,7 +512,7 @@ struct cx8802_dev { | |||
510 | /* cx88-core.c */ | 512 | /* cx88-core.c */ |
511 | 513 | ||
512 | extern void cx88_print_irqbits(char *name, char *tag, char **strings, | 514 | extern void cx88_print_irqbits(char *name, char *tag, char **strings, |
513 | u32 bits, u32 mask); | 515 | int len, u32 bits, u32 mask); |
514 | 516 | ||
515 | extern int cx88_core_irq(struct cx88_core *core, u32 status); | 517 | extern int cx88_core_irq(struct cx88_core *core, u32 status); |
516 | extern void cx88_wakeup(struct cx88_core *core, | 518 | extern void cx88_wakeup(struct cx88_core *core, |
diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c index d829d8f8c1f6..563a8319e608 100644 --- a/drivers/media/video/em28xx/em28xx-i2c.c +++ b/drivers/media/video/em28xx/em28xx-i2c.c | |||
@@ -523,7 +523,7 @@ static void do_i2c_scan(char *name, struct i2c_client *c) | |||
523 | unsigned char buf; | 523 | unsigned char buf; |
524 | int i, rc; | 524 | int i, rc; |
525 | 525 | ||
526 | for (i = 0; i < 128; i++) { | 526 | for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) { |
527 | c->addr = i; | 527 | c->addr = i; |
528 | rc = i2c_master_recv(c, &buf, 0); | 528 | rc = i2c_master_recv(c, &buf, 0); |
529 | if (rc < 0) | 529 | if (rc < 0) |
diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c index 210582d420f8..ed92b6f7187a 100644 --- a/drivers/media/video/ir-kbd-i2c.c +++ b/drivers/media/video/ir-kbd-i2c.c | |||
@@ -173,7 +173,7 @@ static int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw, | |||
173 | return -EIO; | 173 | return -EIO; |
174 | } | 174 | } |
175 | 175 | ||
176 | for (start = 0; start<4; start++) { | 176 | for (start = 0; start < ARRAY_SIZE(b); start++) { |
177 | if (b[start] == marker) { | 177 | if (b[start] == marker) { |
178 | code=b[(start+parity_offset+1)%4]; | 178 | code=b[(start+parity_offset+1)%4]; |
179 | parity=b[(start+parity_offset)%4]; | 179 | parity=b[(start+parity_offset)%4]; |
diff --git a/drivers/media/video/ivtv/Kconfig b/drivers/media/video/ivtv/Kconfig new file mode 100644 index 000000000000..e854f3f1b70f --- /dev/null +++ b/drivers/media/video/ivtv/Kconfig | |||
@@ -0,0 +1,26 @@ | |||
1 | config VIDEO_IVTV | ||
2 | tristate "Conexant cx23416/cx23415 MPEG encoder/decoder support" | ||
3 | depends on VIDEO_V4L1 && VIDEO_V4L2 && USB && I2C && EXPERIMENTAL | ||
4 | select FW_LOADER | ||
5 | select VIDEO_TUNER | ||
6 | select VIDEO_TVEEPROM | ||
7 | select VIDEO_CX2341X | ||
8 | select VIDEO_CX25840 | ||
9 | select VIDEO_MSP3400 | ||
10 | select VIDEO_SAA711X | ||
11 | select VIDEO_SAA7127 | ||
12 | select VIDEO_TVAUDIO | ||
13 | select VIDEO_CS53L32A | ||
14 | select VIDEO_WM8775 | ||
15 | select VIDEO_WM8739 | ||
16 | select VIDEO_UPD64031A | ||
17 | select VIDEO_UPD64083 | ||
18 | ---help--- | ||
19 | This is a video4linux driver for Conexant cx23416 or cx23416 based | ||
20 | PCI personal video recorder devices. | ||
21 | |||
22 | This is used in devices such as the Hauppauge PVR-150/250/350/500 | ||
23 | cards. | ||
24 | |||
25 | To compile this driver as a module, choose M here: the | ||
26 | module will be called ivtv. | ||
diff --git a/drivers/media/video/ivtv/Makefile b/drivers/media/video/ivtv/Makefile new file mode 100644 index 000000000000..7e95148fbf4f --- /dev/null +++ b/drivers/media/video/ivtv/Makefile | |||
@@ -0,0 +1,7 @@ | |||
1 | ivtv-objs := ivtv-audio.o ivtv-cards.o ivtv-controls.o \ | ||
2 | ivtv-driver.o ivtv-fileops.o ivtv-firmware.o \ | ||
3 | ivtv-gpio.o ivtv-i2c.o ivtv-ioctl.o ivtv-irq.o \ | ||
4 | ivtv-mailbox.o ivtv-queue.o ivtv-streams.o ivtv-udma.o \ | ||
5 | ivtv-vbi.o ivtv-video.o ivtv-yuv.o | ||
6 | |||
7 | obj-$(CONFIG_VIDEO_IVTV) += ivtv.o | ||
diff --git a/drivers/media/video/ivtv/ivtv-audio.c b/drivers/media/video/ivtv/ivtv-audio.c new file mode 100644 index 000000000000..d702b8b539a1 --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-audio.c | |||
@@ -0,0 +1,74 @@ | |||
1 | /* | ||
2 | Audio-related ivtv functions. | ||
3 | Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> | ||
4 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | #include "ivtv-driver.h" | ||
22 | #include "ivtv-mailbox.h" | ||
23 | #include "ivtv-i2c.h" | ||
24 | #include "ivtv-gpio.h" | ||
25 | #include "ivtv-cards.h" | ||
26 | #include "ivtv-audio.h" | ||
27 | #include <media/msp3400.h> | ||
28 | #include <linux/videodev.h> | ||
29 | |||
30 | /* Selects the audio input and output according to the current | ||
31 | settings. */ | ||
32 | int ivtv_audio_set_io(struct ivtv *itv) | ||
33 | { | ||
34 | struct v4l2_routing route; | ||
35 | u32 audio_input; | ||
36 | int mux_input; | ||
37 | |||
38 | /* Determine which input to use */ | ||
39 | if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) { | ||
40 | audio_input = itv->card->radio_input.audio_input; | ||
41 | mux_input = itv->card->radio_input.muxer_input; | ||
42 | } else { | ||
43 | audio_input = itv->card->audio_inputs[itv->audio_input].audio_input; | ||
44 | mux_input = itv->card->audio_inputs[itv->audio_input].muxer_input; | ||
45 | } | ||
46 | |||
47 | /* handle muxer chips */ | ||
48 | route.input = mux_input; | ||
49 | route.output = 0; | ||
50 | ivtv_i2c_hw(itv, itv->card->hw_muxer, VIDIOC_INT_S_AUDIO_ROUTING, &route); | ||
51 | |||
52 | route.input = audio_input; | ||
53 | if (itv->card->hw_audio & IVTV_HW_MSP34XX) { | ||
54 | route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1); | ||
55 | } | ||
56 | return ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, &route); | ||
57 | } | ||
58 | |||
59 | void ivtv_audio_set_route(struct ivtv *itv, struct v4l2_routing *route) | ||
60 | { | ||
61 | ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, route); | ||
62 | } | ||
63 | |||
64 | void ivtv_audio_set_audio_clock_freq(struct ivtv *itv, u8 freq) | ||
65 | { | ||
66 | static u32 freqs[3] = { 44100, 48000, 32000 }; | ||
67 | |||
68 | /* The audio clock of the digitizer must match the codec sample | ||
69 | rate otherwise you get some very strange effects. */ | ||
70 | if (freq > 2) | ||
71 | return; | ||
72 | ivtv_call_i2c_clients(itv, VIDIOC_INT_AUDIO_CLOCK_FREQ, &freqs[freq]); | ||
73 | } | ||
74 | |||
diff --git a/drivers/media/video/ivtv/ivtv-audio.h b/drivers/media/video/ivtv/ivtv-audio.h new file mode 100644 index 000000000000..9c42846d8124 --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-audio.h | |||
@@ -0,0 +1,23 @@ | |||
1 | /* | ||
2 | Audio-related ivtv functions. | ||
3 | Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> | ||
4 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | int ivtv_audio_set_io(struct ivtv *itv); | ||
22 | void ivtv_audio_set_route(struct ivtv *itv, struct v4l2_routing *route); | ||
23 | void ivtv_audio_set_audio_clock_freq(struct ivtv *itv, u8 freq); | ||
diff --git a/drivers/media/video/ivtv/ivtv-cards.c b/drivers/media/video/ivtv/ivtv-cards.c new file mode 100644 index 000000000000..8eab02083887 --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-cards.c | |||
@@ -0,0 +1,964 @@ | |||
1 | /* | ||
2 | Functions to query card hardware | ||
3 | Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> | ||
4 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | #include "ivtv-driver.h" | ||
22 | #include "ivtv-cards.h" | ||
23 | #include "ivtv-i2c.h" | ||
24 | |||
25 | #include <media/msp3400.h> | ||
26 | #include <media/wm8775.h> | ||
27 | #include <media/cs53l32a.h> | ||
28 | #include <media/cx25840.h> | ||
29 | #include <media/upd64031a.h> | ||
30 | |||
31 | #define MSP_TUNER MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1, \ | ||
32 | MSP_DSP_IN_TUNER, MSP_DSP_IN_TUNER) | ||
33 | #define MSP_SCART1 MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1, \ | ||
34 | MSP_DSP_IN_SCART, MSP_DSP_IN_SCART) | ||
35 | #define MSP_SCART2 MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1, \ | ||
36 | MSP_DSP_IN_SCART, MSP_DSP_IN_SCART) | ||
37 | #define MSP_SCART3 MSP_INPUT(MSP_IN_SCART3, MSP_IN_TUNER1, \ | ||
38 | MSP_DSP_IN_SCART, MSP_DSP_IN_SCART) | ||
39 | #define MSP_MONO MSP_INPUT(MSP_IN_MONO, MSP_IN_TUNER1, \ | ||
40 | MSP_DSP_IN_SCART, MSP_DSP_IN_SCART) | ||
41 | |||
42 | /********************** card configuration *******************************/ | ||
43 | |||
44 | /* Please add new PCI IDs to: http://pci-ids.ucw.cz/iii | ||
45 | This keeps the PCI ID database up to date. Note that the entries | ||
46 | must be added under vendor 0x4444 (Conexant) as subsystem IDs. | ||
47 | New vendor IDs should still be added to the vendor ID list. */ | ||
48 | |||
49 | /* Hauppauge PVR-250 cards */ | ||
50 | |||
51 | /* Note: for Hauppauge cards the tveeprom information is used instead of PCI IDs */ | ||
52 | static const struct ivtv_card ivtv_card_pvr250 = { | ||
53 | .type = IVTV_CARD_PVR_250, | ||
54 | .name = "Hauppauge WinTV PVR-250", | ||
55 | .v4l2_capabilities = IVTV_CAP_ENCODER, | ||
56 | .hw_video = IVTV_HW_SAA7115, | ||
57 | .hw_audio = IVTV_HW_MSP34XX, | ||
58 | .hw_audio_ctrl = IVTV_HW_MSP34XX, | ||
59 | .hw_all = IVTV_HW_MSP34XX | IVTV_HW_SAA7115 | | ||
60 | IVTV_HW_TVEEPROM | IVTV_HW_TUNER, | ||
61 | .video_inputs = { | ||
62 | { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 }, | ||
63 | { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, | ||
64 | { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE0 }, | ||
65 | { IVTV_CARD_INPUT_SVIDEO2, 2, IVTV_SAA71XX_SVIDEO1 }, | ||
66 | { IVTV_CARD_INPUT_COMPOSITE2, 2, IVTV_SAA71XX_COMPOSITE1 }, | ||
67 | { IVTV_CARD_INPUT_COMPOSITE3, 1, IVTV_SAA71XX_COMPOSITE5 }, | ||
68 | }, | ||
69 | .audio_inputs = { | ||
70 | { IVTV_CARD_INPUT_AUD_TUNER, MSP_TUNER }, | ||
71 | { IVTV_CARD_INPUT_LINE_IN1, MSP_SCART1 }, | ||
72 | { IVTV_CARD_INPUT_LINE_IN2, MSP_SCART3 }, | ||
73 | }, | ||
74 | .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, MSP_SCART2 }, | ||
75 | }; | ||
76 | |||
77 | /* ------------------------------------------------------------------------- */ | ||
78 | |||
79 | /* Hauppauge PVR-350 cards */ | ||
80 | |||
81 | /* Outputs for Hauppauge PVR350 cards */ | ||
82 | static struct ivtv_card_output ivtv_pvr350_outputs[] = { | ||
83 | { | ||
84 | .name = "S-Video + Composite", | ||
85 | .video_output = 0, | ||
86 | }, { | ||
87 | .name = "Composite", | ||
88 | .video_output = 1, | ||
89 | }, { | ||
90 | .name = "S-Video", | ||
91 | .video_output = 2, | ||
92 | }, { | ||
93 | .name = "RGB", | ||
94 | .video_output = 3, | ||
95 | }, { | ||
96 | .name = "YUV C", | ||
97 | .video_output = 4, | ||
98 | }, { | ||
99 | .name = "YUV V", | ||
100 | .video_output = 5, | ||
101 | } | ||
102 | }; | ||
103 | |||
104 | static const struct ivtv_card ivtv_card_pvr350 = { | ||
105 | .type = IVTV_CARD_PVR_350, | ||
106 | .name = "Hauppauge WinTV PVR-350", | ||
107 | .v4l2_capabilities = IVTV_CAP_ENCODER | IVTV_CAP_DECODER, | ||
108 | .video_outputs = ivtv_pvr350_outputs, | ||
109 | .nof_outputs = ARRAY_SIZE(ivtv_pvr350_outputs), | ||
110 | .hw_video = IVTV_HW_SAA7115, | ||
111 | .hw_audio = IVTV_HW_MSP34XX, | ||
112 | .hw_audio_ctrl = IVTV_HW_MSP34XX, | ||
113 | .hw_all = IVTV_HW_MSP34XX | IVTV_HW_SAA7115 | | ||
114 | IVTV_HW_SAA7127 | IVTV_HW_TVEEPROM | IVTV_HW_TUNER, | ||
115 | .video_inputs = { | ||
116 | { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 }, | ||
117 | { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, | ||
118 | { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE0 }, | ||
119 | { IVTV_CARD_INPUT_SVIDEO2, 2, IVTV_SAA71XX_SVIDEO1 }, | ||
120 | { IVTV_CARD_INPUT_COMPOSITE2, 2, IVTV_SAA71XX_COMPOSITE1 }, | ||
121 | { IVTV_CARD_INPUT_COMPOSITE3, 1, IVTV_SAA71XX_COMPOSITE5 }, | ||
122 | }, | ||
123 | .audio_inputs = { | ||
124 | { IVTV_CARD_INPUT_AUD_TUNER, MSP_TUNER }, | ||
125 | { IVTV_CARD_INPUT_LINE_IN1, MSP_SCART1 }, | ||
126 | { IVTV_CARD_INPUT_LINE_IN2, MSP_SCART3 }, | ||
127 | }, | ||
128 | .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, MSP_SCART2 }, | ||
129 | }; | ||
130 | |||
131 | /* PVR-350 V1 boards have a different audio tuner input and use a | ||
132 | saa7114 instead of a saa7115. | ||
133 | Note that the info below comes from a pre-production model so it may | ||
134 | not be correct. Especially the audio behaves strangely (mono only it seems) */ | ||
135 | static const struct ivtv_card ivtv_card_pvr350_v1 = { | ||
136 | .type = IVTV_CARD_PVR_350_V1, | ||
137 | .name = "Hauppauge WinTV PVR-350 (V1)", | ||
138 | .v4l2_capabilities = IVTV_CAP_ENCODER | IVTV_CAP_DECODER, | ||
139 | .video_outputs = ivtv_pvr350_outputs, | ||
140 | .nof_outputs = ARRAY_SIZE(ivtv_pvr350_outputs), | ||
141 | .hw_video = IVTV_HW_SAA7114, | ||
142 | .hw_audio = IVTV_HW_MSP34XX, | ||
143 | .hw_audio_ctrl = IVTV_HW_MSP34XX, | ||
144 | .hw_all = IVTV_HW_MSP34XX | IVTV_HW_SAA7114 | | ||
145 | IVTV_HW_SAA7127 | IVTV_HW_TVEEPROM | IVTV_HW_TUNER, | ||
146 | .video_inputs = { | ||
147 | { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 }, | ||
148 | { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, | ||
149 | { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE0 }, | ||
150 | { IVTV_CARD_INPUT_SVIDEO2, 2, IVTV_SAA71XX_SVIDEO1 }, | ||
151 | { IVTV_CARD_INPUT_COMPOSITE2, 2, IVTV_SAA71XX_COMPOSITE1 }, | ||
152 | { IVTV_CARD_INPUT_COMPOSITE3, 1, IVTV_SAA71XX_COMPOSITE5 }, | ||
153 | }, | ||
154 | .audio_inputs = { | ||
155 | { IVTV_CARD_INPUT_AUD_TUNER, MSP_MONO }, | ||
156 | { IVTV_CARD_INPUT_LINE_IN1, MSP_SCART1 }, | ||
157 | { IVTV_CARD_INPUT_LINE_IN2, MSP_SCART3 }, | ||
158 | }, | ||
159 | .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, MSP_SCART2 }, | ||
160 | }; | ||
161 | |||
162 | /* ------------------------------------------------------------------------- */ | ||
163 | |||
164 | /* Hauppauge PVR-150/PVR-500 cards */ | ||
165 | |||
166 | static const struct ivtv_card ivtv_card_pvr150 = { | ||
167 | .type = IVTV_CARD_PVR_150, | ||
168 | .name = "Hauppauge WinTV PVR-150", | ||
169 | .v4l2_capabilities = IVTV_CAP_ENCODER, | ||
170 | .hw_video = IVTV_HW_CX25840, | ||
171 | .hw_audio = IVTV_HW_CX25840, | ||
172 | .hw_audio_ctrl = IVTV_HW_CX25840, | ||
173 | .hw_muxer = IVTV_HW_WM8775, | ||
174 | .hw_all = IVTV_HW_WM8775 | IVTV_HW_CX25840 | | ||
175 | IVTV_HW_TVEEPROM | IVTV_HW_TUNER, | ||
176 | .video_inputs = { | ||
177 | { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE7 }, | ||
178 | { IVTV_CARD_INPUT_SVIDEO1, 1, CX25840_SVIDEO1 }, | ||
179 | { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE3 }, | ||
180 | { IVTV_CARD_INPUT_SVIDEO2, 2, CX25840_SVIDEO2 }, | ||
181 | { IVTV_CARD_INPUT_COMPOSITE2, 2, CX25840_COMPOSITE4 }, | ||
182 | }, | ||
183 | .audio_inputs = { | ||
184 | { IVTV_CARD_INPUT_AUD_TUNER, | ||
185 | CX25840_AUDIO8, WM8775_AIN2 }, | ||
186 | { IVTV_CARD_INPUT_LINE_IN1, | ||
187 | CX25840_AUDIO_SERIAL, WM8775_AIN2 }, | ||
188 | { IVTV_CARD_INPUT_LINE_IN2, | ||
189 | CX25840_AUDIO_SERIAL, WM8775_AIN3 }, | ||
190 | }, | ||
191 | .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, | ||
192 | CX25840_AUDIO_SERIAL, WM8775_AIN4 }, | ||
193 | /* apparently needed for the IR blaster */ | ||
194 | .gpio_init = { .direction = 0x1f01, .initial_value = 0x26f3 }, | ||
195 | }; | ||
196 | |||
197 | /* ------------------------------------------------------------------------- */ | ||
198 | |||
199 | /* AVerMedia M179 cards */ | ||
200 | |||
201 | static const struct ivtv_card_pci_info ivtv_pci_m179[] = { | ||
202 | { PCI_DEVICE_ID_IVTV15, IVTV_PCI_ID_AVERMEDIA, 0xa3cf }, | ||
203 | { PCI_DEVICE_ID_IVTV15, IVTV_PCI_ID_AVERMEDIA, 0xa3ce }, | ||
204 | { 0, 0, 0 } | ||
205 | }; | ||
206 | |||
207 | static const struct ivtv_card ivtv_card_m179 = { | ||
208 | .type = IVTV_CARD_M179, | ||
209 | .name = "AVerMedia M179", | ||
210 | .v4l2_capabilities = IVTV_CAP_ENCODER, | ||
211 | .hw_video = IVTV_HW_SAA7114, | ||
212 | .hw_audio = IVTV_HW_GPIO, | ||
213 | .hw_audio_ctrl = IVTV_HW_GPIO, | ||
214 | .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7114 | IVTV_HW_TUNER, | ||
215 | .video_inputs = { | ||
216 | { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 }, | ||
217 | { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, | ||
218 | { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE3 }, | ||
219 | }, | ||
220 | .audio_inputs = { | ||
221 | { IVTV_CARD_INPUT_AUD_TUNER, IVTV_GPIO_TUNER }, | ||
222 | { IVTV_CARD_INPUT_LINE_IN1, IVTV_GPIO_LINE_IN }, | ||
223 | }, | ||
224 | .gpio_init = { .direction = 0xe380, .initial_value = 0x8290 }, | ||
225 | .gpio_audio_input = { .mask = 0x8040, .tuner = 0x8000, .linein = 0x0000 }, | ||
226 | .gpio_audio_mute = { .mask = 0x2000, .mute = 0x2000 }, | ||
227 | .gpio_audio_mode = { .mask = 0x4300, .mono = 0x4000, .stereo = 0x0200, | ||
228 | .lang1 = 0x0200, .lang2 = 0x0100, .both = 0x0000 }, | ||
229 | .gpio_audio_freq = { .mask = 0x0018, .f32000 = 0x0000, | ||
230 | .f44100 = 0x0008, .f48000 = 0x0010 }, | ||
231 | .gpio_audio_detect = { .mask = 0x4000, .stereo = 0x0000 }, | ||
232 | .tuners = { | ||
233 | /* As far as we know all M179 cards use this tuner */ | ||
234 | { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_NTSC }, | ||
235 | }, | ||
236 | .pci_list = ivtv_pci_m179, | ||
237 | }; | ||
238 | |||
239 | /* ------------------------------------------------------------------------- */ | ||
240 | |||
241 | /* Yuan MPG600/Kuroutoshikou ITVC16-STVLP cards */ | ||
242 | |||
243 | static const struct ivtv_card_pci_info ivtv_pci_mpg600[] = { | ||
244 | { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN1, 0xfff3 }, | ||
245 | { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN1, 0xffff }, | ||
246 | { 0, 0, 0 } | ||
247 | }; | ||
248 | |||
249 | static const struct ivtv_card ivtv_card_mpg600 = { | ||
250 | .type = IVTV_CARD_MPG600, | ||
251 | .name = "Yuan MPG600, Kuroutoshikou ITVC16-STVLP", | ||
252 | .v4l2_capabilities = IVTV_CAP_ENCODER, | ||
253 | .hw_video = IVTV_HW_SAA7115, | ||
254 | .hw_audio = IVTV_HW_GPIO, | ||
255 | .hw_audio_ctrl = IVTV_HW_GPIO, | ||
256 | .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7115 | IVTV_HW_TUNER, | ||
257 | .video_inputs = { | ||
258 | { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 }, | ||
259 | { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, | ||
260 | { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE3 }, | ||
261 | }, | ||
262 | .audio_inputs = { | ||
263 | { IVTV_CARD_INPUT_AUD_TUNER, IVTV_GPIO_TUNER }, | ||
264 | { IVTV_CARD_INPUT_LINE_IN1, IVTV_GPIO_LINE_IN }, | ||
265 | }, | ||
266 | .gpio_init = { .direction = 0x3080, .initial_value = 0x0004 }, | ||
267 | .gpio_audio_input = { .mask = 0x3000, .tuner = 0x0000, .linein = 0x2000 }, | ||
268 | .gpio_audio_mute = { .mask = 0x0001, .mute = 0x0001 }, | ||
269 | .gpio_audio_mode = { .mask = 0x000e, .mono = 0x0006, .stereo = 0x0004, | ||
270 | .lang1 = 0x0004, .lang2 = 0x0000, .both = 0x0008 }, | ||
271 | .gpio_audio_detect = { .mask = 0x0900, .stereo = 0x0100 }, | ||
272 | .tuners = { | ||
273 | /* The PAL tuner is confirmed */ | ||
274 | { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FQ1216ME }, | ||
275 | { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 }, | ||
276 | }, | ||
277 | .pci_list = ivtv_pci_mpg600, | ||
278 | }; | ||
279 | |||
280 | /* ------------------------------------------------------------------------- */ | ||
281 | |||
282 | /* Yuan MPG160/Kuroutoshikou ITVC15-STVLP cards */ | ||
283 | |||
284 | static const struct ivtv_card_pci_info ivtv_pci_mpg160[] = { | ||
285 | { PCI_DEVICE_ID_IVTV15, IVTV_PCI_ID_YUAN1, 0 }, | ||
286 | { PCI_DEVICE_ID_IVTV15, IVTV_PCI_ID_IODATA, 0x40a0 }, | ||
287 | { 0, 0, 0 } | ||
288 | }; | ||
289 | |||
290 | static const struct ivtv_card ivtv_card_mpg160 = { | ||
291 | .type = IVTV_CARD_MPG160, | ||
292 | .name = "YUAN MPG160, Kuroutoshikou ITVC15-STVLP, I/O Data GV-M2TV/PCI", | ||
293 | .v4l2_capabilities = IVTV_CAP_ENCODER, | ||
294 | .hw_video = IVTV_HW_SAA7114, | ||
295 | .hw_audio = IVTV_HW_GPIO, | ||
296 | .hw_audio_ctrl = IVTV_HW_GPIO, | ||
297 | .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7114 | IVTV_HW_TUNER, | ||
298 | .video_inputs = { | ||
299 | { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 }, | ||
300 | { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, | ||
301 | { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE3 }, | ||
302 | }, | ||
303 | .audio_inputs = { | ||
304 | { IVTV_CARD_INPUT_AUD_TUNER, IVTV_GPIO_TUNER }, | ||
305 | { IVTV_CARD_INPUT_LINE_IN1, IVTV_GPIO_LINE_IN }, | ||
306 | }, | ||
307 | .gpio_init = { .direction = 0x7080, .initial_value = 0x400c }, | ||
308 | .gpio_audio_input = { .mask = 0x3000, .tuner = 0x0000, .linein = 0x2000 }, | ||
309 | .gpio_audio_mute = { .mask = 0x0001, .mute = 0x0001 }, | ||
310 | .gpio_audio_mode = { .mask = 0x000e, .mono = 0x0006, .stereo = 0x0004, | ||
311 | .lang1 = 0x0004, .lang2 = 0x0000, .both = 0x0008 }, | ||
312 | .gpio_audio_detect = { .mask = 0x0900, .stereo = 0x0100 }, | ||
313 | .tuners = { | ||
314 | { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FQ1216ME }, | ||
315 | { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 }, | ||
316 | }, | ||
317 | .pci_list = ivtv_pci_mpg160, | ||
318 | }; | ||
319 | |||
320 | /* ------------------------------------------------------------------------- */ | ||
321 | |||
322 | /* Yuan PG600/Diamond PVR-550 cards */ | ||
323 | |||
324 | static const struct ivtv_card_pci_info ivtv_pci_pg600[] = { | ||
325 | { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_DIAMONDMM, 0x0070 }, | ||
326 | { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN3, 0x0600 }, | ||
327 | { 0, 0, 0 } | ||
328 | }; | ||
329 | |||
330 | static const struct ivtv_card ivtv_card_pg600 = { | ||
331 | .type = IVTV_CARD_PG600, | ||
332 | .name = "Yuan PG600, Diamond PVR-550", | ||
333 | .v4l2_capabilities = IVTV_CAP_ENCODER, | ||
334 | .hw_video = IVTV_HW_CX25840, | ||
335 | .hw_audio = IVTV_HW_CX25840, | ||
336 | .hw_audio_ctrl = IVTV_HW_CX25840, | ||
337 | .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER, | ||
338 | .video_inputs = { | ||
339 | { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 }, | ||
340 | { IVTV_CARD_INPUT_SVIDEO1, 1, | ||
341 | CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 }, | ||
342 | { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 }, | ||
343 | }, | ||
344 | .audio_inputs = { | ||
345 | { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 }, | ||
346 | { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL }, | ||
347 | }, | ||
348 | .tuners = { | ||
349 | { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FQ1216ME }, | ||
350 | { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 }, | ||
351 | }, | ||
352 | .pci_list = ivtv_pci_pg600, | ||
353 | }; | ||
354 | |||
355 | /* ------------------------------------------------------------------------- */ | ||
356 | |||
357 | /* Adaptec VideOh! AVC-2410 card */ | ||
358 | |||
359 | static const struct ivtv_card_pci_info ivtv_pci_avc2410[] = { | ||
360 | { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_ADAPTEC, 0x0093 }, | ||
361 | { 0, 0, 0 } | ||
362 | }; | ||
363 | |||
364 | static const struct ivtv_card ivtv_card_avc2410 = { | ||
365 | .type = IVTV_CARD_AVC2410, | ||
366 | .name = "Adaptec VideOh! AVC-2410", | ||
367 | .v4l2_capabilities = IVTV_CAP_ENCODER, | ||
368 | .hw_video = IVTV_HW_SAA7115, | ||
369 | .hw_audio = IVTV_HW_MSP34XX, | ||
370 | .hw_audio_ctrl = IVTV_HW_MSP34XX, | ||
371 | .hw_muxer = IVTV_HW_CS53L32A, | ||
372 | .hw_all = IVTV_HW_MSP34XX | IVTV_HW_CS53L32A | | ||
373 | IVTV_HW_SAA7115 | IVTV_HW_TUNER, | ||
374 | .video_inputs = { | ||
375 | { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 }, | ||
376 | { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, | ||
377 | { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE3 }, | ||
378 | }, | ||
379 | .audio_inputs = { | ||
380 | { IVTV_CARD_INPUT_AUD_TUNER, | ||
381 | MSP_TUNER, CS53L32A_IN0 }, | ||
382 | { IVTV_CARD_INPUT_LINE_IN1, | ||
383 | MSP_SCART1, CS53L32A_IN2 }, | ||
384 | }, | ||
385 | /* This card has no eeprom and in fact the Windows driver relies | ||
386 | on the country/region setting of the user to decide which tuner | ||
387 | is available. */ | ||
388 | .tuners = { | ||
389 | /* This tuner has been verified for the AVC2410 */ | ||
390 | { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, | ||
391 | /* This is a good guess, but I'm not totally sure this is | ||
392 | the correct tuner for NTSC. */ | ||
393 | { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 }, | ||
394 | }, | ||
395 | .pci_list = ivtv_pci_avc2410, | ||
396 | }; | ||
397 | |||
398 | /* ------------------------------------------------------------------------- */ | ||
399 | |||
400 | /* Adaptec VideOh! AVC-2010 card */ | ||
401 | |||
402 | static const struct ivtv_card_pci_info ivtv_pci_avc2010[] = { | ||
403 | { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_ADAPTEC, 0x0092 }, | ||
404 | { 0, 0, 0 } | ||
405 | }; | ||
406 | |||
407 | static const struct ivtv_card ivtv_card_avc2010 = { | ||
408 | .type = IVTV_CARD_AVC2010, | ||
409 | .name = "Adaptec VideOh! AVC-2010", | ||
410 | .v4l2_capabilities = IVTV_CAP_ENCODER, | ||
411 | .hw_video = IVTV_HW_SAA7115, | ||
412 | .hw_audio = IVTV_HW_CS53L32A, | ||
413 | .hw_audio_ctrl = IVTV_HW_CS53L32A, | ||
414 | .hw_all = IVTV_HW_CS53L32A | IVTV_HW_SAA7115, | ||
415 | .video_inputs = { | ||
416 | { IVTV_CARD_INPUT_SVIDEO1, 0, IVTV_SAA71XX_SVIDEO0 }, | ||
417 | { IVTV_CARD_INPUT_COMPOSITE1, 0, IVTV_SAA71XX_COMPOSITE3 }, | ||
418 | }, | ||
419 | .audio_inputs = { | ||
420 | { IVTV_CARD_INPUT_LINE_IN1, CS53L32A_IN2 }, | ||
421 | }, | ||
422 | /* Does not have a tuner */ | ||
423 | .pci_list = ivtv_pci_avc2010, | ||
424 | }; | ||
425 | |||
426 | /* ------------------------------------------------------------------------- */ | ||
427 | |||
428 | /* Nagase Transgear 5000TV card */ | ||
429 | |||
430 | static const struct ivtv_card_pci_info ivtv_pci_tg5000tv[] = { | ||
431 | { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xbfff }, | ||
432 | { 0, 0, 0 } | ||
433 | }; | ||
434 | |||
435 | static const struct ivtv_card ivtv_card_tg5000tv = { | ||
436 | .type = IVTV_CARD_TG5000TV, | ||
437 | .name = "Nagase Transgear 5000TV", | ||
438 | .v4l2_capabilities = IVTV_CAP_ENCODER, | ||
439 | .hw_video = IVTV_HW_SAA7114 | IVTV_HW_UPD64031A | IVTV_HW_UPD6408X | | ||
440 | IVTV_HW_GPIO, | ||
441 | .hw_audio = IVTV_HW_GPIO, | ||
442 | .hw_audio_ctrl = IVTV_HW_GPIO, | ||
443 | .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7114 | IVTV_HW_TUNER | | ||
444 | IVTV_HW_UPD64031A | IVTV_HW_UPD6408X, | ||
445 | .video_inputs = { | ||
446 | { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_SVIDEO0 }, | ||
447 | { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO2 }, | ||
448 | { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_SVIDEO2 }, | ||
449 | }, | ||
450 | .audio_inputs = { | ||
451 | { IVTV_CARD_INPUT_AUD_TUNER, IVTV_GPIO_TUNER }, | ||
452 | { IVTV_CARD_INPUT_LINE_IN1, IVTV_GPIO_LINE_IN }, | ||
453 | }, | ||
454 | .gr_config = UPD64031A_VERTICAL_EXTERNAL, | ||
455 | .gpio_init = { .direction = 0xe080, .initial_value = 0x8000 }, | ||
456 | .gpio_audio_input = { .mask = 0x8080, .tuner = 0x8000, .linein = 0x0080 }, | ||
457 | .gpio_audio_mute = { .mask = 0x6000, .mute = 0x6000 }, | ||
458 | .gpio_audio_mode = { .mask = 0x4300, .mono = 0x4000, .stereo = 0x0200, | ||
459 | .lang1 = 0x0300, .lang2 = 0x0000, .both = 0x0200 }, | ||
460 | .gpio_video_input = { .mask = 0x0030, .tuner = 0x0000, | ||
461 | .composite = 0x0010, .svideo = 0x0020 }, | ||
462 | .tuners = { | ||
463 | { .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FQ1286 }, | ||
464 | }, | ||
465 | .pci_list = ivtv_pci_tg5000tv, | ||
466 | }; | ||
467 | |||
468 | /* ------------------------------------------------------------------------- */ | ||
469 | |||
470 | /* AOpen VA2000MAX-SNT6 card */ | ||
471 | |||
472 | static const struct ivtv_card_pci_info ivtv_pci_va2000[] = { | ||
473 | { PCI_DEVICE_ID_IVTV16, 0, 0xff5f }, | ||
474 | { 0, 0, 0 } | ||
475 | }; | ||
476 | |||
477 | static const struct ivtv_card ivtv_card_va2000 = { | ||
478 | .type = IVTV_CARD_VA2000MAX_SNT6, | ||
479 | .name = "AOpen VA2000MAX-SNT6", | ||
480 | .v4l2_capabilities = IVTV_CAP_ENCODER, | ||
481 | .hw_video = IVTV_HW_SAA7115 | IVTV_HW_UPD6408X, | ||
482 | .hw_audio = IVTV_HW_MSP34XX, | ||
483 | .hw_audio_ctrl = IVTV_HW_MSP34XX, | ||
484 | .hw_all = IVTV_HW_MSP34XX | IVTV_HW_SAA7115 | | ||
485 | IVTV_HW_UPD6408X | IVTV_HW_TUNER, | ||
486 | .video_inputs = { | ||
487 | { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_SVIDEO0 }, | ||
488 | }, | ||
489 | .audio_inputs = { | ||
490 | { IVTV_CARD_INPUT_AUD_TUNER, MSP_TUNER }, | ||
491 | }, | ||
492 | .tuners = { | ||
493 | { .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FQ1286 }, | ||
494 | }, | ||
495 | .pci_list = ivtv_pci_va2000, | ||
496 | }; | ||
497 | |||
498 | /* ------------------------------------------------------------------------- */ | ||
499 | |||
500 | /* Yuan MPG600GR/Kuroutoshikou CX23416GYC-STVLP cards */ | ||
501 | |||
502 | static const struct ivtv_card_pci_info ivtv_pci_cx23416gyc[] = { | ||
503 | { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN1, 0x0600 }, | ||
504 | { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN4, 0x0600 }, | ||
505 | { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_MELCO, 0x0523 }, | ||
506 | { 0, 0, 0 } | ||
507 | }; | ||
508 | |||
509 | static const struct ivtv_card ivtv_card_cx23416gyc = { | ||
510 | .type = IVTV_CARD_CX23416GYC, | ||
511 | .name = "Yuan MPG600GR, Kuroutoshikou CX23416GYC-STVLP", | ||
512 | .v4l2_capabilities = IVTV_CAP_ENCODER, | ||
513 | .hw_video = IVTV_HW_SAA717X | IVTV_HW_GPIO | | ||
514 | IVTV_HW_UPD64031A | IVTV_HW_UPD6408X, | ||
515 | .hw_audio = IVTV_HW_SAA717X, | ||
516 | .hw_audio_ctrl = IVTV_HW_SAA717X, | ||
517 | .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA717X | IVTV_HW_TUNER | | ||
518 | IVTV_HW_UPD64031A | IVTV_HW_UPD6408X, | ||
519 | .video_inputs = { | ||
520 | { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_SVIDEO3 | | ||
521 | IVTV_SAA717X_TUNER_FLAG }, | ||
522 | { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, | ||
523 | { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_SVIDEO3 }, | ||
524 | }, | ||
525 | .audio_inputs = { | ||
526 | { IVTV_CARD_INPUT_AUD_TUNER, IVTV_SAA717X_IN2 }, | ||
527 | { IVTV_CARD_INPUT_LINE_IN1, IVTV_SAA717X_IN0 }, | ||
528 | }, | ||
529 | .gr_config = UPD64031A_VERTICAL_EXTERNAL, | ||
530 | .gpio_init = { .direction = 0xf880, .initial_value = 0x8800 }, | ||
531 | .gpio_video_input = { .mask = 0x0020, .tuner = 0x0000, | ||
532 | .composite = 0x0020, .svideo = 0x0020 }, | ||
533 | .gpio_audio_freq = { .mask = 0xc000, .f32000 = 0x0000, | ||
534 | .f44100 = 0x4000, .f48000 = 0x8000 }, | ||
535 | .tuners = { | ||
536 | { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, | ||
537 | { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 }, | ||
538 | }, | ||
539 | .pci_list = ivtv_pci_cx23416gyc, | ||
540 | }; | ||
541 | |||
542 | static const struct ivtv_card ivtv_card_cx23416gyc_nogr = { | ||
543 | .type = IVTV_CARD_CX23416GYC_NOGR, | ||
544 | .name = "Yuan MPG600GR, Kuroutoshikou CX23416GYC-STVLP (no GR)", | ||
545 | .v4l2_capabilities = IVTV_CAP_ENCODER, | ||
546 | .hw_video = IVTV_HW_SAA717X | IVTV_HW_GPIO | IVTV_HW_UPD6408X, | ||
547 | .hw_audio = IVTV_HW_SAA717X, | ||
548 | .hw_audio_ctrl = IVTV_HW_SAA717X, | ||
549 | .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA717X | IVTV_HW_TUNER | | ||
550 | IVTV_HW_UPD6408X, | ||
551 | .video_inputs = { | ||
552 | { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 | | ||
553 | IVTV_SAA717X_TUNER_FLAG }, | ||
554 | { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, | ||
555 | { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE0 }, | ||
556 | }, | ||
557 | .audio_inputs = { | ||
558 | { IVTV_CARD_INPUT_AUD_TUNER, IVTV_SAA717X_IN2 }, | ||
559 | { IVTV_CARD_INPUT_LINE_IN1, IVTV_SAA717X_IN0 }, | ||
560 | }, | ||
561 | .gpio_init = { .direction = 0xf880, .initial_value = 0x8800 }, | ||
562 | .gpio_video_input = { .mask = 0x0020, .tuner = 0x0000, | ||
563 | .composite = 0x0020, .svideo = 0x0020 }, | ||
564 | .gpio_audio_freq = { .mask = 0xc000, .f32000 = 0x0000, | ||
565 | .f44100 = 0x4000, .f48000 = 0x8000 }, | ||
566 | .tuners = { | ||
567 | { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, | ||
568 | { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 }, | ||
569 | }, | ||
570 | }; | ||
571 | |||
572 | static const struct ivtv_card ivtv_card_cx23416gyc_nogrycs = { | ||
573 | .type = IVTV_CARD_CX23416GYC_NOGRYCS, | ||
574 | .name = "Yuan MPG600GR, Kuroutoshikou CX23416GYC-STVLP (no GR/YCS)", | ||
575 | .v4l2_capabilities = IVTV_CAP_ENCODER, | ||
576 | .hw_video = IVTV_HW_SAA717X | IVTV_HW_GPIO, | ||
577 | .hw_audio = IVTV_HW_SAA717X, | ||
578 | .hw_audio_ctrl = IVTV_HW_SAA717X, | ||
579 | .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA717X | IVTV_HW_TUNER, | ||
580 | .video_inputs = { | ||
581 | { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 | | ||
582 | IVTV_SAA717X_TUNER_FLAG }, | ||
583 | { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, | ||
584 | { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE0 }, | ||
585 | }, | ||
586 | .audio_inputs = { | ||
587 | { IVTV_CARD_INPUT_AUD_TUNER, IVTV_SAA717X_IN2 }, | ||
588 | { IVTV_CARD_INPUT_LINE_IN1, IVTV_SAA717X_IN0 }, | ||
589 | }, | ||
590 | .gpio_init = { .direction = 0xf880, .initial_value = 0x8800 }, | ||
591 | .gpio_video_input = { .mask = 0x0020, .tuner = 0x0000, | ||
592 | .composite = 0x0020, .svideo = 0x0020 }, | ||
593 | .gpio_audio_freq = { .mask = 0xc000, .f32000 = 0x0000, | ||
594 | .f44100 = 0x4000, .f48000 = 0x8000 }, | ||
595 | .tuners = { | ||
596 | { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, | ||
597 | { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 }, | ||
598 | }, | ||
599 | }; | ||
600 | |||
601 | /* ------------------------------------------------------------------------- */ | ||
602 | |||
603 | /* I/O Data GV-MVP/RX & GV-MVP/RX2W (dual tuner) cards */ | ||
604 | |||
605 | static const struct ivtv_card_pci_info ivtv_pci_gv_mvprx[] = { | ||
606 | { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_IODATA, 0xd01e }, | ||
607 | { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_IODATA, 0xd038 }, /* 2W unit #1 */ | ||
608 | { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_IODATA, 0xd039 }, /* 2W unit #2 */ | ||
609 | { 0, 0, 0 } | ||
610 | }; | ||
611 | |||
612 | static const struct ivtv_card ivtv_card_gv_mvprx = { | ||
613 | .type = IVTV_CARD_GV_MVPRX, | ||
614 | .name = "I/O Data GV-MVP/RX, GV-MVP/RX2W (dual tuner)", | ||
615 | .v4l2_capabilities = IVTV_CAP_ENCODER, | ||
616 | .hw_video = IVTV_HW_SAA7115 | IVTV_HW_UPD64031A | IVTV_HW_UPD6408X, | ||
617 | .hw_audio = IVTV_HW_GPIO, | ||
618 | .hw_audio_ctrl = IVTV_HW_WM8739, | ||
619 | .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7115 | IVTV_HW_TVAUDIO | | ||
620 | IVTV_HW_TUNER | IVTV_HW_WM8739 | | ||
621 | IVTV_HW_UPD64031A | IVTV_HW_UPD6408X, | ||
622 | .video_inputs = { | ||
623 | { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_SVIDEO0 }, | ||
624 | { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO1 }, | ||
625 | { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_SVIDEO2 }, | ||
626 | }, | ||
627 | .audio_inputs = { | ||
628 | { IVTV_CARD_INPUT_AUD_TUNER, IVTV_GPIO_TUNER }, | ||
629 | { IVTV_CARD_INPUT_LINE_IN1, IVTV_GPIO_LINE_IN }, | ||
630 | }, | ||
631 | .gpio_init = { .direction = 0xc301, .initial_value = 0x0200 }, | ||
632 | .gpio_audio_input = { .mask = 0xffff, .tuner = 0x0200, .linein = 0x0300 }, | ||
633 | .tuners = { | ||
634 | /* This card has the Panasonic VP27 tuner */ | ||
635 | { .std = V4L2_STD_525_60, .tuner = TUNER_PANASONIC_VP27 }, | ||
636 | }, | ||
637 | .pci_list = ivtv_pci_gv_mvprx, | ||
638 | }; | ||
639 | |||
640 | /* ------------------------------------------------------------------------- */ | ||
641 | |||
642 | /* I/O Data GV-MVP/RX2E card */ | ||
643 | |||
644 | static const struct ivtv_card_pci_info ivtv_pci_gv_mvprx2e[] = { | ||
645 | { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_IODATA, 0xd025 }, | ||
646 | {0, 0, 0} | ||
647 | }; | ||
648 | |||
649 | static const struct ivtv_card ivtv_card_gv_mvprx2e = { | ||
650 | .type = IVTV_CARD_GV_MVPRX2E, | ||
651 | .name = "I/O Data GV-MVP/RX2E", | ||
652 | .v4l2_capabilities = IVTV_CAP_ENCODER, | ||
653 | .hw_video = IVTV_HW_SAA7115, | ||
654 | .hw_audio = IVTV_HW_GPIO, | ||
655 | .hw_audio_ctrl = IVTV_HW_WM8739, | ||
656 | .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7115 | IVTV_HW_TUNER | | ||
657 | IVTV_HW_TVAUDIO | IVTV_HW_WM8739, | ||
658 | .video_inputs = { | ||
659 | { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 }, | ||
660 | { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, | ||
661 | { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE3 }, | ||
662 | }, | ||
663 | .audio_inputs = { | ||
664 | { IVTV_CARD_INPUT_AUD_TUNER, IVTV_GPIO_TUNER }, | ||
665 | { IVTV_CARD_INPUT_LINE_IN1, IVTV_GPIO_LINE_IN }, | ||
666 | }, | ||
667 | .gpio_init = { .direction = 0xc301, .initial_value = 0x0200 }, | ||
668 | .gpio_audio_input = { .mask = 0xffff, .tuner = 0x0200, .linein = 0x0300 }, | ||
669 | .tuners = { | ||
670 | /* This card has the Panasonic VP27 tuner */ | ||
671 | { .std = V4L2_STD_525_60, .tuner = TUNER_PANASONIC_VP27 }, | ||
672 | }, | ||
673 | .pci_list = ivtv_pci_gv_mvprx2e, | ||
674 | }; | ||
675 | |||
676 | /* ------------------------------------------------------------------------- */ | ||
677 | |||
678 | /* GotVIEW PCI DVD card */ | ||
679 | |||
680 | static const struct ivtv_card_pci_info ivtv_pci_gotview_pci_dvd[] = { | ||
681 | { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN1, 0x0600 }, | ||
682 | { 0, 0, 0 } | ||
683 | }; | ||
684 | |||
685 | static const struct ivtv_card ivtv_card_gotview_pci_dvd = { | ||
686 | .type = IVTV_CARD_GOTVIEW_PCI_DVD, | ||
687 | .name = "GotView PCI DVD", | ||
688 | .v4l2_capabilities = IVTV_CAP_ENCODER, | ||
689 | .hw_video = IVTV_HW_SAA717X, | ||
690 | .hw_audio = IVTV_HW_SAA717X, | ||
691 | .hw_audio_ctrl = IVTV_HW_SAA717X, | ||
692 | .hw_all = IVTV_HW_SAA717X | IVTV_HW_TUNER, | ||
693 | .video_inputs = { | ||
694 | { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE1 }, /* pin 116 */ | ||
695 | { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 }, /* pin 114/109 */ | ||
696 | { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_COMPOSITE3 }, /* pin 118 */ | ||
697 | }, | ||
698 | .audio_inputs = { | ||
699 | { IVTV_CARD_INPUT_AUD_TUNER, IVTV_SAA717X_IN0 }, | ||
700 | { IVTV_CARD_INPUT_LINE_IN1, IVTV_SAA717X_IN2 }, | ||
701 | }, | ||
702 | .gpio_init = { .direction = 0xf000, .initial_value = 0xA000 }, | ||
703 | .tuners = { | ||
704 | /* This card has a Philips FQ1216ME MK3 tuner */ | ||
705 | { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, | ||
706 | }, | ||
707 | .pci_list = ivtv_pci_gotview_pci_dvd, | ||
708 | }; | ||
709 | |||
710 | /* ------------------------------------------------------------------------- */ | ||
711 | |||
712 | /* GotVIEW PCI DVD2 Deluxe card */ | ||
713 | |||
714 | static const struct ivtv_card_pci_info ivtv_pci_gotview_pci_dvd2[] = { | ||
715 | { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_GOTVIEW1, 0x0600 }, | ||
716 | { 0, 0, 0 } | ||
717 | }; | ||
718 | |||
719 | static const struct ivtv_card ivtv_card_gotview_pci_dvd2 = { | ||
720 | .type = IVTV_CARD_GOTVIEW_PCI_DVD2, | ||
721 | .name = "GotView PCI DVD2 Deluxe", | ||
722 | .v4l2_capabilities = IVTV_CAP_ENCODER, | ||
723 | .hw_video = IVTV_HW_CX25840, | ||
724 | .hw_audio = IVTV_HW_CX25840, | ||
725 | .hw_audio_ctrl = IVTV_HW_CX25840, | ||
726 | .hw_muxer = IVTV_HW_GPIO, | ||
727 | .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER, | ||
728 | .video_inputs = { | ||
729 | { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 }, | ||
730 | { IVTV_CARD_INPUT_SVIDEO1, 1, | ||
731 | CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 }, | ||
732 | { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 }, | ||
733 | }, | ||
734 | .audio_inputs = { | ||
735 | { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5, 0 }, | ||
736 | { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, 1 }, | ||
737 | }, | ||
738 | .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, 2 }, | ||
739 | .gpio_init = { .direction = 0x0800, .initial_value = 0 }, | ||
740 | .gpio_audio_input = { .mask = 0x0800, .tuner = 0, .linein = 0, .radio = 0x0800 }, | ||
741 | .tuners = { | ||
742 | /* This card has a Philips FQ1216ME MK5 tuner */ | ||
743 | { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, | ||
744 | }, | ||
745 | .pci_list = ivtv_pci_gotview_pci_dvd2, | ||
746 | }; | ||
747 | |||
748 | /* ------------------------------------------------------------------------- */ | ||
749 | |||
750 | /* Yuan MPC622 miniPCI card */ | ||
751 | |||
752 | static const struct ivtv_card_pci_info ivtv_pci_yuan_mpc622[] = { | ||
753 | { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN2, 0xd998 }, | ||
754 | { 0, 0, 0 } | ||
755 | }; | ||
756 | |||
757 | static const struct ivtv_card ivtv_card_yuan_mpc622 = { | ||
758 | .type = IVTV_CARD_YUAN_MPC622, | ||
759 | .name = "Yuan MPC622", | ||
760 | .v4l2_capabilities = IVTV_CAP_ENCODER, | ||
761 | .hw_video = IVTV_HW_CX25840, | ||
762 | .hw_audio = IVTV_HW_CX25840, | ||
763 | .hw_audio_ctrl = IVTV_HW_CX25840, | ||
764 | .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER, | ||
765 | .video_inputs = { | ||
766 | { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 }, | ||
767 | { IVTV_CARD_INPUT_SVIDEO1, 1, | ||
768 | CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 }, | ||
769 | { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 }, | ||
770 | }, | ||
771 | .audio_inputs = { | ||
772 | { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 }, | ||
773 | { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL }, | ||
774 | }, | ||
775 | .gpio_init = { .direction = 0x00ff, .initial_value = 0x0002 }, | ||
776 | .tuners = { | ||
777 | /* This card has the TDA8290/TDA8275 tuner chips */ | ||
778 | { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_TDA8290 }, | ||
779 | }, | ||
780 | .pci_list = ivtv_pci_yuan_mpc622, | ||
781 | }; | ||
782 | |||
783 | /* ------------------------------------------------------------------------- */ | ||
784 | |||
785 | /* DIGITAL COWBOY DCT-MTVP1 card */ | ||
786 | |||
787 | static const struct ivtv_card_pci_info ivtv_pci_dctmvtvp1[] = { | ||
788 | { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xbfff }, | ||
789 | { 0, 0, 0 } | ||
790 | }; | ||
791 | |||
792 | static const struct ivtv_card ivtv_card_dctmvtvp1 = { | ||
793 | .type = IVTV_CARD_DCTMTVP1, | ||
794 | .name = "Digital Cowboy DCT-MTVP1", | ||
795 | .v4l2_capabilities = IVTV_CAP_ENCODER, | ||
796 | .hw_video = IVTV_HW_SAA7115 | IVTV_HW_UPD64031A | IVTV_HW_UPD6408X | | ||
797 | IVTV_HW_GPIO, | ||
798 | .hw_audio = IVTV_HW_GPIO, | ||
799 | .hw_audio_ctrl = IVTV_HW_GPIO, | ||
800 | .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7115 | IVTV_HW_TUNER | | ||
801 | IVTV_HW_UPD64031A | IVTV_HW_UPD6408X, | ||
802 | .video_inputs = { | ||
803 | { IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_SVIDEO0 }, | ||
804 | { IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO2 }, | ||
805 | { IVTV_CARD_INPUT_COMPOSITE1, 1, IVTV_SAA71XX_SVIDEO2 }, | ||
806 | }, | ||
807 | .audio_inputs = { | ||
808 | { IVTV_CARD_INPUT_AUD_TUNER, IVTV_GPIO_TUNER }, | ||
809 | { IVTV_CARD_INPUT_LINE_IN1, IVTV_GPIO_LINE_IN }, | ||
810 | }, | ||
811 | .gpio_init = { .direction = 0xe080, .initial_value = 0x8000 }, | ||
812 | .gpio_audio_input = { .mask = 0x8080, .tuner = 0x8000, .linein = 0x0080 }, | ||
813 | .gpio_audio_mute = { .mask = 0x6000, .mute = 0x6000 }, | ||
814 | .gpio_audio_mode = { .mask = 0x4300, .mono = 0x4000, .stereo = 0x0200, | ||
815 | .lang1 = 0x0300, .lang2 = 0x0000, .both = 0x0200 }, | ||
816 | .gpio_video_input = { .mask = 0x0030, .tuner = 0x0000, | ||
817 | .composite = 0x0010, .svideo = 0x0020}, | ||
818 | .tuners = { | ||
819 | { .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FQ1286 }, | ||
820 | }, | ||
821 | .pci_list = ivtv_pci_dctmvtvp1, | ||
822 | }; | ||
823 | |||
824 | /* ------------------------------------------------------------------------- */ | ||
825 | |||
826 | #ifdef HAVE_XC3028 | ||
827 | |||
828 | /* Yuan PG600-2/GotView PCI DVD Lite/Club3D ZAP-TV1x01 cards */ | ||
829 | |||
830 | static const struct ivtv_card_pci_info ivtv_pci_pg600v2[] = { | ||
831 | { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN3, 0x0600 }, | ||
832 | { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_GOTVIEW2, 0x0600 }, | ||
833 | { 0, 0, 0 } | ||
834 | }; | ||
835 | |||
836 | static const struct ivtv_card ivtv_card_pg600v2 = { | ||
837 | .type = IVTV_CARD_PG600V2, | ||
838 | .name = "Yuan PG600-2, GotView PCI DVD Lite, Club3D ZAP-TV1x01", | ||
839 | .v4l2_capabilities = IVTV_CAP_ENCODER, | ||
840 | .hw_video = IVTV_HW_CX25840, | ||
841 | .hw_audio = IVTV_HW_CX25840, | ||
842 | .hw_audio_ctrl = IVTV_HW_CX25840, | ||
843 | .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER, | ||
844 | .video_inputs = { | ||
845 | { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 }, | ||
846 | { IVTV_CARD_INPUT_SVIDEO1, 1, | ||
847 | CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 }, | ||
848 | }, | ||
849 | .audio_inputs = { | ||
850 | { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 }, | ||
851 | { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL }, | ||
852 | }, | ||
853 | .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 }, | ||
854 | .tuners = { | ||
855 | { .std = V4L2_STD_ALL, .tuner = TUNER_XCEIVE_XC3028 }, | ||
856 | }, | ||
857 | .gpio_init = { .direction = 0x1000, .initial_value = 0x1000 }, /* tuner reset */ | ||
858 | .pci_list = ivtv_pci_pg600v2, | ||
859 | }; | ||
860 | #endif | ||
861 | |||
862 | static const struct ivtv_card *ivtv_card_list[] = { | ||
863 | &ivtv_card_pvr250, | ||
864 | &ivtv_card_pvr350, | ||
865 | &ivtv_card_pvr150, | ||
866 | &ivtv_card_m179, | ||
867 | &ivtv_card_mpg600, | ||
868 | &ivtv_card_mpg160, | ||
869 | &ivtv_card_pg600, | ||
870 | &ivtv_card_avc2410, | ||
871 | &ivtv_card_avc2010, | ||
872 | &ivtv_card_tg5000tv, | ||
873 | &ivtv_card_va2000, | ||
874 | &ivtv_card_cx23416gyc, | ||
875 | &ivtv_card_gv_mvprx, | ||
876 | &ivtv_card_gv_mvprx2e, | ||
877 | &ivtv_card_gotview_pci_dvd, | ||
878 | &ivtv_card_gotview_pci_dvd2, | ||
879 | &ivtv_card_yuan_mpc622, | ||
880 | &ivtv_card_dctmvtvp1, | ||
881 | #ifdef HAVE_XC3028 | ||
882 | &ivtv_card_pg600v2, | ||
883 | #endif | ||
884 | |||
885 | /* Variations of standard cards but with the same PCI IDs. | ||
886 | These cards must come last in this list. */ | ||
887 | &ivtv_card_pvr350_v1, | ||
888 | &ivtv_card_cx23416gyc_nogr, | ||
889 | &ivtv_card_cx23416gyc_nogrycs, | ||
890 | }; | ||
891 | |||
892 | const struct ivtv_card *ivtv_get_card(u16 index) | ||
893 | { | ||
894 | if (index >= ARRAY_SIZE(ivtv_card_list)) | ||
895 | return NULL; | ||
896 | return ivtv_card_list[index]; | ||
897 | } | ||
898 | |||
899 | int ivtv_get_input(struct ivtv *itv, u16 index, struct v4l2_input *input) | ||
900 | { | ||
901 | const struct ivtv_card_video_input *card_input = itv->card->video_inputs + index; | ||
902 | static const char * const input_strs[] = { | ||
903 | "Tuner 1", | ||
904 | "S-Video 1", | ||
905 | "S-Video 2", | ||
906 | "Composite 1", | ||
907 | "Composite 2", | ||
908 | "Composite 3" | ||
909 | }; | ||
910 | |||
911 | memset(input, 0, sizeof(*input)); | ||
912 | if (index >= itv->nof_inputs) | ||
913 | return -EINVAL; | ||
914 | input->index = index; | ||
915 | strcpy(input->name, input_strs[card_input->video_type - 1]); | ||
916 | input->type = (card_input->video_type == IVTV_CARD_INPUT_VID_TUNER ? | ||
917 | V4L2_INPUT_TYPE_TUNER : V4L2_INPUT_TYPE_CAMERA); | ||
918 | input->audioset = (1 << itv->nof_audio_inputs) - 1; | ||
919 | input->std = (input->type == V4L2_INPUT_TYPE_TUNER) ? | ||
920 | itv->tuner_std : V4L2_STD_ALL; | ||
921 | return 0; | ||
922 | } | ||
923 | |||
924 | int ivtv_get_output(struct ivtv *itv, u16 index, struct v4l2_output *output) | ||
925 | { | ||
926 | const struct ivtv_card_output *card_output = itv->card->video_outputs + index; | ||
927 | |||
928 | memset(output, 0, sizeof(*output)); | ||
929 | if (index >= itv->card->nof_outputs) | ||
930 | return -EINVAL; | ||
931 | output->index = index; | ||
932 | strcpy(output->name, card_output->name); | ||
933 | output->type = V4L2_OUTPUT_TYPE_ANALOG; | ||
934 | output->audioset = 1; | ||
935 | output->std = V4L2_STD_ALL; | ||
936 | return 0; | ||
937 | } | ||
938 | |||
939 | int ivtv_get_audio_input(struct ivtv *itv, u16 index, struct v4l2_audio *audio) | ||
940 | { | ||
941 | const struct ivtv_card_audio_input *aud_input = itv->card->audio_inputs + index; | ||
942 | static const char * const input_strs[] = { | ||
943 | "Tuner 1", | ||
944 | "Line In 1", | ||
945 | "Line In 2" | ||
946 | }; | ||
947 | |||
948 | memset(audio, 0, sizeof(*audio)); | ||
949 | if (index >= itv->nof_audio_inputs) | ||
950 | return -EINVAL; | ||
951 | strcpy(audio->name, input_strs[aud_input->audio_type - 1]); | ||
952 | audio->index = index; | ||
953 | audio->capability = V4L2_AUDCAP_STEREO; | ||
954 | return 0; | ||
955 | } | ||
956 | |||
957 | int ivtv_get_audio_output(struct ivtv *itv, u16 index, struct v4l2_audioout *aud_output) | ||
958 | { | ||
959 | memset(aud_output, 0, sizeof(*aud_output)); | ||
960 | if (itv->card->video_outputs == NULL || index != 0) | ||
961 | return -EINVAL; | ||
962 | strcpy(aud_output->name, "A/V Audio Out"); | ||
963 | return 0; | ||
964 | } | ||
diff --git a/drivers/media/video/ivtv/ivtv-cards.h b/drivers/media/video/ivtv/ivtv-cards.h new file mode 100644 index 000000000000..15012f88b802 --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-cards.h | |||
@@ -0,0 +1,207 @@ | |||
1 | /* | ||
2 | Functions to query card hardware | ||
3 | Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> | ||
4 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | /* hardware flags */ | ||
22 | #define IVTV_HW_CX25840 (1 << 0) | ||
23 | #define IVTV_HW_SAA7115 (1 << 1) | ||
24 | #define IVTV_HW_SAA7127 (1 << 2) | ||
25 | #define IVTV_HW_MSP34XX (1 << 3) | ||
26 | #define IVTV_HW_TUNER (1 << 4) | ||
27 | #define IVTV_HW_WM8775 (1 << 5) | ||
28 | #define IVTV_HW_CS53L32A (1 << 6) | ||
29 | #define IVTV_HW_TVEEPROM (1 << 7) | ||
30 | #define IVTV_HW_SAA7114 (1 << 8) | ||
31 | #define IVTV_HW_TVAUDIO (1 << 9) | ||
32 | #define IVTV_HW_UPD64031A (1 << 10) | ||
33 | #define IVTV_HW_UPD6408X (1 << 11) | ||
34 | #define IVTV_HW_SAA717X (1 << 12) | ||
35 | #define IVTV_HW_WM8739 (1 << 13) | ||
36 | #define IVTV_HW_GPIO (1 << 14) | ||
37 | |||
38 | #define IVTV_HW_SAA711X (IVTV_HW_SAA7115 | IVTV_HW_SAA7114) | ||
39 | |||
40 | /* video inputs */ | ||
41 | #define IVTV_CARD_INPUT_VID_TUNER 1 | ||
42 | #define IVTV_CARD_INPUT_SVIDEO1 2 | ||
43 | #define IVTV_CARD_INPUT_SVIDEO2 3 | ||
44 | #define IVTV_CARD_INPUT_COMPOSITE1 4 | ||
45 | #define IVTV_CARD_INPUT_COMPOSITE2 5 | ||
46 | #define IVTV_CARD_INPUT_COMPOSITE3 6 | ||
47 | |||
48 | /* audio inputs */ | ||
49 | #define IVTV_CARD_INPUT_AUD_TUNER 1 | ||
50 | #define IVTV_CARD_INPUT_LINE_IN1 2 | ||
51 | #define IVTV_CARD_INPUT_LINE_IN2 3 | ||
52 | |||
53 | #define IVTV_CARD_MAX_VIDEO_INPUTS 6 | ||
54 | #define IVTV_CARD_MAX_AUDIO_INPUTS 3 | ||
55 | #define IVTV_CARD_MAX_TUNERS 2 | ||
56 | |||
57 | /* SAA71XX HW inputs */ | ||
58 | #define IVTV_SAA71XX_COMPOSITE0 0 | ||
59 | #define IVTV_SAA71XX_COMPOSITE1 1 | ||
60 | #define IVTV_SAA71XX_COMPOSITE2 2 | ||
61 | #define IVTV_SAA71XX_COMPOSITE3 3 | ||
62 | #define IVTV_SAA71XX_COMPOSITE4 4 | ||
63 | #define IVTV_SAA71XX_COMPOSITE5 5 | ||
64 | #define IVTV_SAA71XX_SVIDEO0 6 | ||
65 | #define IVTV_SAA71XX_SVIDEO1 7 | ||
66 | #define IVTV_SAA71XX_SVIDEO2 8 | ||
67 | #define IVTV_SAA71XX_SVIDEO3 9 | ||
68 | |||
69 | /* SAA717X needs to mark the tuner input by ORing with this flag */ | ||
70 | #define IVTV_SAA717X_TUNER_FLAG 0x80 | ||
71 | |||
72 | /* Dummy HW input */ | ||
73 | #define IVTV_DUMMY_AUDIO 0 | ||
74 | |||
75 | /* GPIO HW inputs */ | ||
76 | #define IVTV_GPIO_TUNER 0 | ||
77 | #define IVTV_GPIO_LINE_IN 1 | ||
78 | |||
79 | /* SAA717X HW inputs */ | ||
80 | #define IVTV_SAA717X_IN0 0 | ||
81 | #define IVTV_SAA717X_IN1 1 | ||
82 | #define IVTV_SAA717X_IN2 2 | ||
83 | |||
84 | /* V4L2 capability aliases */ | ||
85 | #define IVTV_CAP_ENCODER (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | \ | ||
86 | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | V4L2_CAP_VBI_CAPTURE | \ | ||
87 | V4L2_CAP_SLICED_VBI_CAPTURE) | ||
88 | #define IVTV_CAP_DECODER (V4L2_CAP_VBI_OUTPUT | V4L2_CAP_VIDEO_OUTPUT | \ | ||
89 | V4L2_CAP_SLICED_VBI_OUTPUT | V4L2_CAP_VIDEO_OUTPUT_OVERLAY | V4L2_CAP_VIDEO_OUTPUT_POS) | ||
90 | |||
91 | struct ivtv_card_video_input { | ||
92 | u8 video_type; /* video input type */ | ||
93 | u8 audio_index; /* index in ivtv_card_audio_input array */ | ||
94 | u16 video_input; /* hardware video input */ | ||
95 | }; | ||
96 | |||
97 | struct ivtv_card_audio_input { | ||
98 | u8 audio_type; /* audio input type */ | ||
99 | u32 audio_input; /* hardware audio input */ | ||
100 | u16 muxer_input; /* hardware muxer input for boards with a | ||
101 | multiplexer chip */ | ||
102 | }; | ||
103 | |||
104 | struct ivtv_card_output { | ||
105 | u8 name[32]; | ||
106 | u16 video_output; /* hardware video output */ | ||
107 | }; | ||
108 | |||
109 | struct ivtv_card_pci_info { | ||
110 | u16 device; | ||
111 | u16 subsystem_vendor; | ||
112 | u16 subsystem_device; | ||
113 | }; | ||
114 | |||
115 | /* GPIO definitions */ | ||
116 | |||
117 | /* The mask is the set of bits used by the operation */ | ||
118 | |||
119 | struct ivtv_gpio_init { /* set initial GPIO DIR and OUT values */ | ||
120 | u16 direction; /* DIR setting. Leave to 0 if no init is needed */ | ||
121 | u16 initial_value; | ||
122 | }; | ||
123 | |||
124 | struct ivtv_gpio_video_input { /* select tuner/line in input */ | ||
125 | u16 mask; /* leave to 0 if not supported */ | ||
126 | u16 tuner; | ||
127 | u16 composite; | ||
128 | u16 svideo; | ||
129 | }; | ||
130 | |||
131 | struct ivtv_gpio_audio_input { /* select tuner/line in input */ | ||
132 | u16 mask; /* leave to 0 if not supported */ | ||
133 | u16 tuner; | ||
134 | u16 linein; | ||
135 | u16 radio; | ||
136 | }; | ||
137 | |||
138 | struct ivtv_gpio_audio_mute { | ||
139 | u16 mask; /* leave to 0 if not supported */ | ||
140 | u16 mute; /* set this value to mute, 0 to unmute */ | ||
141 | }; | ||
142 | |||
143 | struct ivtv_gpio_audio_mode { | ||
144 | u16 mask; /* leave to 0 if not supported */ | ||
145 | u16 mono; /* set audio to mono */ | ||
146 | u16 stereo; /* set audio to stereo */ | ||
147 | u16 lang1; /* set audio to the first language */ | ||
148 | u16 lang2; /* set audio to the second language */ | ||
149 | u16 both; /* both languages are output */ | ||
150 | }; | ||
151 | |||
152 | struct ivtv_gpio_audio_freq { | ||
153 | u16 mask; /* leave to 0 if not supported */ | ||
154 | u16 f32000; | ||
155 | u16 f44100; | ||
156 | u16 f48000; | ||
157 | }; | ||
158 | |||
159 | struct ivtv_gpio_audio_detect { | ||
160 | u16 mask; /* leave to 0 if not supported */ | ||
161 | u16 stereo; /* if the input matches this value then | ||
162 | stereo is detected */ | ||
163 | }; | ||
164 | |||
165 | struct ivtv_card_tuner { | ||
166 | v4l2_std_id std; /* standard for which the tuner is suitable */ | ||
167 | int tuner; /* tuner ID (from tuner.h) */ | ||
168 | }; | ||
169 | |||
170 | /* for card information/parameters */ | ||
171 | struct ivtv_card { | ||
172 | int type; | ||
173 | char *name; | ||
174 | u32 v4l2_capabilities; | ||
175 | u32 hw_video; /* hardware used to process video */ | ||
176 | u32 hw_audio; /* hardware used to process audio */ | ||
177 | u32 hw_audio_ctrl; /* hardware used for the V4L2 controls (only 1 dev allowed) */ | ||
178 | u32 hw_muxer; /* hardware used to multiplex audio input */ | ||
179 | u32 hw_all; /* all hardware used by the board */ | ||
180 | struct ivtv_card_video_input video_inputs[IVTV_CARD_MAX_VIDEO_INPUTS]; | ||
181 | struct ivtv_card_audio_input audio_inputs[IVTV_CARD_MAX_AUDIO_INPUTS]; | ||
182 | struct ivtv_card_audio_input radio_input; | ||
183 | int nof_outputs; | ||
184 | const struct ivtv_card_output *video_outputs; | ||
185 | u8 gr_config; /* config byte for the ghost reduction device */ | ||
186 | |||
187 | /* GPIO card-specific settings */ | ||
188 | struct ivtv_gpio_init gpio_init; | ||
189 | struct ivtv_gpio_video_input gpio_video_input; | ||
190 | struct ivtv_gpio_audio_input gpio_audio_input; | ||
191 | struct ivtv_gpio_audio_mute gpio_audio_mute; | ||
192 | struct ivtv_gpio_audio_mode gpio_audio_mode; | ||
193 | struct ivtv_gpio_audio_freq gpio_audio_freq; | ||
194 | struct ivtv_gpio_audio_detect gpio_audio_detect; | ||
195 | |||
196 | struct ivtv_card_tuner tuners[IVTV_CARD_MAX_TUNERS]; | ||
197 | |||
198 | /* list of device and subsystem vendor/devices that | ||
199 | correspond to this card type. */ | ||
200 | const struct ivtv_card_pci_info *pci_list; | ||
201 | }; | ||
202 | |||
203 | int ivtv_get_input(struct ivtv *itv, u16 index, struct v4l2_input *input); | ||
204 | int ivtv_get_output(struct ivtv *itv, u16 index, struct v4l2_output *output); | ||
205 | int ivtv_get_audio_input(struct ivtv *itv, u16 index, struct v4l2_audio *input); | ||
206 | int ivtv_get_audio_output(struct ivtv *itv, u16 index, struct v4l2_audioout *output); | ||
207 | const struct ivtv_card *ivtv_get_card(u16 index); | ||
diff --git a/drivers/media/video/ivtv/ivtv-controls.c b/drivers/media/video/ivtv/ivtv-controls.c new file mode 100644 index 000000000000..7a876c3e5b19 --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-controls.c | |||
@@ -0,0 +1,303 @@ | |||
1 | /* | ||
2 | ioctl control functions | ||
3 | Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> | ||
4 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | #include "ivtv-driver.h" | ||
22 | #include "ivtv-cards.h" | ||
23 | #include "ivtv-ioctl.h" | ||
24 | #include "ivtv-audio.h" | ||
25 | #include "ivtv-i2c.h" | ||
26 | #include "ivtv-mailbox.h" | ||
27 | #include "ivtv-controls.h" | ||
28 | |||
29 | static const u32 user_ctrls[] = { | ||
30 | V4L2_CID_USER_CLASS, | ||
31 | V4L2_CID_BRIGHTNESS, | ||
32 | V4L2_CID_CONTRAST, | ||
33 | V4L2_CID_SATURATION, | ||
34 | V4L2_CID_HUE, | ||
35 | V4L2_CID_AUDIO_VOLUME, | ||
36 | V4L2_CID_AUDIO_BALANCE, | ||
37 | V4L2_CID_AUDIO_BASS, | ||
38 | V4L2_CID_AUDIO_TREBLE, | ||
39 | V4L2_CID_AUDIO_MUTE, | ||
40 | V4L2_CID_AUDIO_LOUDNESS, | ||
41 | 0 | ||
42 | }; | ||
43 | |||
44 | static const u32 *ctrl_classes[] = { | ||
45 | user_ctrls, | ||
46 | cx2341x_mpeg_ctrls, | ||
47 | NULL | ||
48 | }; | ||
49 | |||
50 | static int ivtv_queryctrl(struct ivtv *itv, struct v4l2_queryctrl *qctrl) | ||
51 | { | ||
52 | const char *name; | ||
53 | |||
54 | IVTV_DEBUG_IOCTL("VIDIOC_QUERYCTRL(%08x)\n", qctrl->id); | ||
55 | |||
56 | qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id); | ||
57 | if (qctrl->id == 0) | ||
58 | return -EINVAL; | ||
59 | |||
60 | switch (qctrl->id) { | ||
61 | /* Standard V4L2 controls */ | ||
62 | case V4L2_CID_BRIGHTNESS: | ||
63 | case V4L2_CID_HUE: | ||
64 | case V4L2_CID_SATURATION: | ||
65 | case V4L2_CID_CONTRAST: | ||
66 | if (itv->video_dec_func(itv, VIDIOC_QUERYCTRL, qctrl)) | ||
67 | qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; | ||
68 | return 0; | ||
69 | |||
70 | case V4L2_CID_AUDIO_VOLUME: | ||
71 | case V4L2_CID_AUDIO_MUTE: | ||
72 | case V4L2_CID_AUDIO_BALANCE: | ||
73 | case V4L2_CID_AUDIO_BASS: | ||
74 | case V4L2_CID_AUDIO_TREBLE: | ||
75 | case V4L2_CID_AUDIO_LOUDNESS: | ||
76 | if (ivtv_i2c_hw(itv, itv->card->hw_audio_ctrl, VIDIOC_QUERYCTRL, qctrl)) | ||
77 | qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; | ||
78 | return 0; | ||
79 | |||
80 | default: | ||
81 | if (cx2341x_ctrl_query(&itv->params, qctrl)) | ||
82 | qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; | ||
83 | return 0; | ||
84 | } | ||
85 | strncpy(qctrl->name, name, sizeof(qctrl->name) - 1); | ||
86 | qctrl->name[sizeof(qctrl->name) - 1] = 0; | ||
87 | return 0; | ||
88 | } | ||
89 | |||
90 | static int ivtv_querymenu(struct ivtv *itv, struct v4l2_querymenu *qmenu) | ||
91 | { | ||
92 | struct v4l2_queryctrl qctrl; | ||
93 | |||
94 | qctrl.id = qmenu->id; | ||
95 | ivtv_queryctrl(itv, &qctrl); | ||
96 | return v4l2_ctrl_query_menu(qmenu, &qctrl, cx2341x_ctrl_get_menu(qmenu->id)); | ||
97 | } | ||
98 | |||
99 | static int ivtv_s_ctrl(struct ivtv *itv, struct v4l2_control *vctrl) | ||
100 | { | ||
101 | s32 v = vctrl->value; | ||
102 | |||
103 | IVTV_DEBUG_IOCTL("VIDIOC_S_CTRL(%08x, %x)\n", vctrl->id, v); | ||
104 | |||
105 | switch (vctrl->id) { | ||
106 | /* Standard V4L2 controls */ | ||
107 | case V4L2_CID_BRIGHTNESS: | ||
108 | case V4L2_CID_HUE: | ||
109 | case V4L2_CID_SATURATION: | ||
110 | case V4L2_CID_CONTRAST: | ||
111 | return itv->video_dec_func(itv, VIDIOC_S_CTRL, vctrl); | ||
112 | |||
113 | case V4L2_CID_AUDIO_VOLUME: | ||
114 | case V4L2_CID_AUDIO_MUTE: | ||
115 | case V4L2_CID_AUDIO_BALANCE: | ||
116 | case V4L2_CID_AUDIO_BASS: | ||
117 | case V4L2_CID_AUDIO_TREBLE: | ||
118 | case V4L2_CID_AUDIO_LOUDNESS: | ||
119 | return ivtv_i2c_hw(itv, itv->card->hw_audio_ctrl, VIDIOC_S_CTRL, vctrl); | ||
120 | |||
121 | default: | ||
122 | IVTV_DEBUG_IOCTL("invalid control %x\n", vctrl->id); | ||
123 | return -EINVAL; | ||
124 | } | ||
125 | return 0; | ||
126 | } | ||
127 | |||
128 | static int ivtv_g_ctrl(struct ivtv *itv, struct v4l2_control *vctrl) | ||
129 | { | ||
130 | IVTV_DEBUG_IOCTL("VIDIOC_G_CTRL(%08x)\n", vctrl->id); | ||
131 | |||
132 | switch (vctrl->id) { | ||
133 | /* Standard V4L2 controls */ | ||
134 | case V4L2_CID_BRIGHTNESS: | ||
135 | case V4L2_CID_HUE: | ||
136 | case V4L2_CID_SATURATION: | ||
137 | case V4L2_CID_CONTRAST: | ||
138 | return itv->video_dec_func(itv, VIDIOC_G_CTRL, vctrl); | ||
139 | |||
140 | case V4L2_CID_AUDIO_VOLUME: | ||
141 | case V4L2_CID_AUDIO_MUTE: | ||
142 | case V4L2_CID_AUDIO_BALANCE: | ||
143 | case V4L2_CID_AUDIO_BASS: | ||
144 | case V4L2_CID_AUDIO_TREBLE: | ||
145 | case V4L2_CID_AUDIO_LOUDNESS: | ||
146 | return ivtv_i2c_hw(itv, itv->card->hw_audio_ctrl, VIDIOC_G_CTRL, vctrl); | ||
147 | default: | ||
148 | IVTV_DEBUG_IOCTL("invalid control %x\n", vctrl->id); | ||
149 | return -EINVAL; | ||
150 | } | ||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | static int ivtv_setup_vbi_fmt(struct ivtv *itv, enum v4l2_mpeg_stream_vbi_fmt fmt) | ||
155 | { | ||
156 | if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_CAPTURE)) | ||
157 | return -EINVAL; | ||
158 | if (atomic_read(&itv->capturing) > 0) | ||
159 | return -EBUSY; | ||
160 | |||
161 | /* First try to allocate sliced VBI buffers if needed. */ | ||
162 | if (fmt && itv->vbi.sliced_mpeg_data[0] == NULL) { | ||
163 | int i; | ||
164 | |||
165 | for (i = 0; i < IVTV_VBI_FRAMES; i++) { | ||
166 | /* Yuck, hardcoded. Needs to be a define */ | ||
167 | itv->vbi.sliced_mpeg_data[i] = kmalloc(2049, GFP_KERNEL); | ||
168 | if (itv->vbi.sliced_mpeg_data[i] == NULL) { | ||
169 | while (--i >= 0) { | ||
170 | kfree(itv->vbi.sliced_mpeg_data[i]); | ||
171 | itv->vbi.sliced_mpeg_data[i] = NULL; | ||
172 | } | ||
173 | return -ENOMEM; | ||
174 | } | ||
175 | } | ||
176 | } | ||
177 | |||
178 | itv->vbi.insert_mpeg = fmt; | ||
179 | |||
180 | if (itv->vbi.insert_mpeg == 0) { | ||
181 | return 0; | ||
182 | } | ||
183 | /* Need sliced data for mpeg insertion */ | ||
184 | if (get_service_set(itv->vbi.sliced_in) == 0) { | ||
185 | if (itv->is_60hz) | ||
186 | itv->vbi.sliced_in->service_set = V4L2_SLICED_CAPTION_525; | ||
187 | else | ||
188 | itv->vbi.sliced_in->service_set = V4L2_SLICED_WSS_625; | ||
189 | expand_service_set(itv->vbi.sliced_in, itv->is_50hz); | ||
190 | } | ||
191 | return 0; | ||
192 | } | ||
193 | |||
194 | int ivtv_control_ioctls(struct ivtv *itv, unsigned int cmd, void *arg) | ||
195 | { | ||
196 | struct v4l2_control ctrl; | ||
197 | |||
198 | switch (cmd) { | ||
199 | case VIDIOC_QUERYMENU: | ||
200 | IVTV_DEBUG_IOCTL("VIDIOC_QUERYMENU\n"); | ||
201 | return ivtv_querymenu(itv, arg); | ||
202 | |||
203 | case VIDIOC_QUERYCTRL: | ||
204 | return ivtv_queryctrl(itv, arg); | ||
205 | |||
206 | case VIDIOC_S_CTRL: | ||
207 | return ivtv_s_ctrl(itv, arg); | ||
208 | |||
209 | case VIDIOC_G_CTRL: | ||
210 | return ivtv_g_ctrl(itv, arg); | ||
211 | |||
212 | case VIDIOC_S_EXT_CTRLS: | ||
213 | { | ||
214 | struct v4l2_ext_controls *c = arg; | ||
215 | |||
216 | if (c->ctrl_class == V4L2_CTRL_CLASS_USER) { | ||
217 | int i; | ||
218 | int err = 0; | ||
219 | |||
220 | for (i = 0; i < c->count; i++) { | ||
221 | ctrl.id = c->controls[i].id; | ||
222 | ctrl.value = c->controls[i].value; | ||
223 | err = ivtv_s_ctrl(itv, &ctrl); | ||
224 | c->controls[i].value = ctrl.value; | ||
225 | if (err) { | ||
226 | c->error_idx = i; | ||
227 | break; | ||
228 | } | ||
229 | } | ||
230 | return err; | ||
231 | } | ||
232 | IVTV_DEBUG_IOCTL("VIDIOC_S_EXT_CTRLS\n"); | ||
233 | if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) { | ||
234 | struct cx2341x_mpeg_params p = itv->params; | ||
235 | int err = cx2341x_ext_ctrls(&p, arg, cmd); | ||
236 | |||
237 | if (err) | ||
238 | return err; | ||
239 | |||
240 | if (p.video_encoding != itv->params.video_encoding) { | ||
241 | int is_mpeg1 = p.video_encoding == | ||
242 | V4L2_MPEG_VIDEO_ENCODING_MPEG_1; | ||
243 | struct v4l2_format fmt; | ||
244 | |||
245 | /* fix videodecoder resolution */ | ||
246 | fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
247 | fmt.fmt.pix.width = itv->params.width / (is_mpeg1 ? 2 : 1); | ||
248 | fmt.fmt.pix.height = itv->params.height; | ||
249 | itv->video_dec_func(itv, VIDIOC_S_FMT, &fmt); | ||
250 | } | ||
251 | err = cx2341x_update(itv, ivtv_api_func, &itv->params, &p); | ||
252 | if (!err && itv->params.stream_vbi_fmt != p.stream_vbi_fmt) { | ||
253 | err = ivtv_setup_vbi_fmt(itv, p.stream_vbi_fmt); | ||
254 | } | ||
255 | itv->params = p; | ||
256 | itv->dualwatch_stereo_mode = p.audio_properties & 0x0300; | ||
257 | ivtv_audio_set_audio_clock_freq(itv, p.audio_properties & 0x03); | ||
258 | return err; | ||
259 | } | ||
260 | return -EINVAL; | ||
261 | } | ||
262 | |||
263 | case VIDIOC_G_EXT_CTRLS: | ||
264 | { | ||
265 | struct v4l2_ext_controls *c = arg; | ||
266 | |||
267 | if (c->ctrl_class == V4L2_CTRL_CLASS_USER) { | ||
268 | int i; | ||
269 | int err = 0; | ||
270 | |||
271 | for (i = 0; i < c->count; i++) { | ||
272 | ctrl.id = c->controls[i].id; | ||
273 | ctrl.value = c->controls[i].value; | ||
274 | err = ivtv_g_ctrl(itv, &ctrl); | ||
275 | c->controls[i].value = ctrl.value; | ||
276 | if (err) { | ||
277 | c->error_idx = i; | ||
278 | break; | ||
279 | } | ||
280 | } | ||
281 | return err; | ||
282 | } | ||
283 | IVTV_DEBUG_IOCTL("VIDIOC_G_EXT_CTRLS\n"); | ||
284 | if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) | ||
285 | return cx2341x_ext_ctrls(&itv->params, arg, cmd); | ||
286 | return -EINVAL; | ||
287 | } | ||
288 | |||
289 | case VIDIOC_TRY_EXT_CTRLS: | ||
290 | { | ||
291 | struct v4l2_ext_controls *c = arg; | ||
292 | |||
293 | IVTV_DEBUG_IOCTL("VIDIOC_TRY_EXT_CTRLS\n"); | ||
294 | if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) | ||
295 | return cx2341x_ext_ctrls(&itv->params, arg, cmd); | ||
296 | return -EINVAL; | ||
297 | } | ||
298 | |||
299 | default: | ||
300 | return -EINVAL; | ||
301 | } | ||
302 | return 0; | ||
303 | } | ||
diff --git a/drivers/media/video/ivtv/ivtv-controls.h b/drivers/media/video/ivtv/ivtv-controls.h new file mode 100644 index 000000000000..5a11149725ad --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-controls.h | |||
@@ -0,0 +1,21 @@ | |||
1 | /* | ||
2 | ioctl control functions | ||
3 | Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> | ||
4 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | int ivtv_control_ioctls(struct ivtv *itv, unsigned int cmd, void *arg); | ||
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c new file mode 100644 index 000000000000..45b9328a538f --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-driver.c | |||
@@ -0,0 +1,1374 @@ | |||
1 | /* | ||
2 | ivtv driver initialization and card probing | ||
3 | Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> | ||
4 | Copyright (C) 2004 Chris Kennedy <c@groovy.org> | ||
5 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2 of the License, or | ||
10 | (at your option) any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; if not, write to the Free Software | ||
19 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | */ | ||
21 | |||
22 | /* Main Driver file for the ivtv project: | ||
23 | * Driver for the Conexant CX23415/CX23416 chip. | ||
24 | * Author: Kevin Thayer (nufan_wfk at yahoo.com) | ||
25 | * License: GPL | ||
26 | * http://www.ivtvdriver.org | ||
27 | * | ||
28 | * ----- | ||
29 | * MPG600/MPG160 support by T.Adachi <tadachi@tadachi-net.com> | ||
30 | * and Takeru KOMORIYA<komoriya@paken.org> | ||
31 | * | ||
32 | * AVerMedia M179 GPIO info by Chris Pinkham <cpinkham@bc2va.org> | ||
33 | * using information provided by Jiun-Kuei Jung @ AVerMedia. | ||
34 | * | ||
35 | * Kurouto Sikou CX23416GYC-STVLP tested by K.Ohta <alpha292@bremen.or.jp> | ||
36 | * using information from T.Adachi,Takeru KOMORIYA and others :-) | ||
37 | * | ||
38 | * Nagase TRANSGEAR 5000TV, Aopen VA2000MAX-STN6 and I/O data GV-MVP/RX | ||
39 | * version by T.Adachi. Special thanks Mr.Suzuki | ||
40 | */ | ||
41 | |||
42 | #include "ivtv-driver.h" | ||
43 | #include "ivtv-version.h" | ||
44 | #include "ivtv-fileops.h" | ||
45 | #include "ivtv-i2c.h" | ||
46 | #include "ivtv-firmware.h" | ||
47 | #include "ivtv-queue.h" | ||
48 | #include "ivtv-udma.h" | ||
49 | #include "ivtv-irq.h" | ||
50 | #include "ivtv-mailbox.h" | ||
51 | #include "ivtv-streams.h" | ||
52 | #include "ivtv-ioctl.h" | ||
53 | #include "ivtv-cards.h" | ||
54 | #include "ivtv-vbi.h" | ||
55 | #include "ivtv-audio.h" | ||
56 | #include "ivtv-gpio.h" | ||
57 | #include "ivtv-yuv.h" | ||
58 | |||
59 | #include <linux/vermagic.h> | ||
60 | #include <media/tveeprom.h> | ||
61 | #include <media/v4l2-chip-ident.h> | ||
62 | |||
63 | /* var to keep track of the number of array elements in use */ | ||
64 | int ivtv_cards_active = 0; | ||
65 | |||
66 | /* If you have already X v4l cards, then set this to X. This way | ||
67 | the device numbers stay matched. Example: you have a WinTV card | ||
68 | without radio and a PVR-350 with. Normally this would give a | ||
69 | video1 device together with a radio0 device for the PVR. By | ||
70 | setting this to 1 you ensure that radio0 is now also radio1. */ | ||
71 | int ivtv_first_minor = 0; | ||
72 | |||
73 | /* Master variable for all ivtv info */ | ||
74 | struct ivtv *ivtv_cards[IVTV_MAX_CARDS]; | ||
75 | |||
76 | /* Protects ivtv_cards_active */ | ||
77 | spinlock_t ivtv_cards_lock = SPIN_LOCK_UNLOCKED; | ||
78 | |||
79 | /* add your revision and whatnot here */ | ||
80 | static struct pci_device_id ivtv_pci_tbl[] __devinitdata = { | ||
81 | {PCI_VENDOR_ID_ICOMP, PCI_DEVICE_ID_IVTV15, | ||
82 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
83 | {PCI_VENDOR_ID_ICOMP, PCI_DEVICE_ID_IVTV16, | ||
84 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | ||
85 | {0,} | ||
86 | }; | ||
87 | |||
88 | MODULE_DEVICE_TABLE(pci,ivtv_pci_tbl); | ||
89 | |||
90 | const u32 yuv_offset[4] = { | ||
91 | IVTV_YUV_BUFFER_OFFSET, | ||
92 | IVTV_YUV_BUFFER_OFFSET_1, | ||
93 | IVTV_YUV_BUFFER_OFFSET_2, | ||
94 | IVTV_YUV_BUFFER_OFFSET_3 | ||
95 | }; | ||
96 | |||
97 | /* Parameter declarations */ | ||
98 | static int cardtype[IVTV_MAX_CARDS]; | ||
99 | static int tuner[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; | ||
100 | static int radio[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; | ||
101 | |||
102 | static int cardtype_c = 1; | ||
103 | static int tuner_c = 1; | ||
104 | static int radio_c = 1; | ||
105 | static char pal[] = "--"; | ||
106 | static char secam[] = "--"; | ||
107 | static char ntsc[] = "-"; | ||
108 | |||
109 | /* Buffers */ | ||
110 | static int enc_mpg_buffers = IVTV_DEFAULT_ENC_MPG_BUFFERS; | ||
111 | static int enc_yuv_buffers = IVTV_DEFAULT_ENC_YUV_BUFFERS; | ||
112 | static int enc_vbi_buffers = IVTV_DEFAULT_ENC_VBI_BUFFERS; | ||
113 | static int enc_pcm_buffers = IVTV_DEFAULT_ENC_PCM_BUFFERS; | ||
114 | static int dec_mpg_buffers = IVTV_DEFAULT_DEC_MPG_BUFFERS; | ||
115 | static int dec_yuv_buffers = IVTV_DEFAULT_DEC_YUV_BUFFERS; | ||
116 | static int dec_vbi_buffers = IVTV_DEFAULT_DEC_VBI_BUFFERS; | ||
117 | |||
118 | static int ivtv_yuv_mode = 0; | ||
119 | static int ivtv_yuv_threshold=-1; | ||
120 | static int ivtv_pci_latency = 1; | ||
121 | |||
122 | int ivtv_debug = 0; | ||
123 | |||
124 | static int newi2c = -1; | ||
125 | |||
126 | module_param_array(tuner, int, &tuner_c, 0644); | ||
127 | module_param_array(radio, bool, &radio_c, 0644); | ||
128 | module_param_array(cardtype, int, &cardtype_c, 0644); | ||
129 | module_param_string(pal, pal, sizeof(pal), 0644); | ||
130 | module_param_string(secam, secam, sizeof(secam), 0644); | ||
131 | module_param_string(ntsc, ntsc, sizeof(ntsc), 0644); | ||
132 | module_param_named(debug,ivtv_debug, int, 0644); | ||
133 | module_param(ivtv_pci_latency, int, 0644); | ||
134 | module_param(ivtv_yuv_mode, int, 0644); | ||
135 | module_param(ivtv_yuv_threshold, int, 0644); | ||
136 | module_param(ivtv_first_minor, int, 0644); | ||
137 | |||
138 | module_param(enc_mpg_buffers, int, 0644); | ||
139 | module_param(enc_yuv_buffers, int, 0644); | ||
140 | module_param(enc_vbi_buffers, int, 0644); | ||
141 | module_param(enc_pcm_buffers, int, 0644); | ||
142 | module_param(dec_mpg_buffers, int, 0644); | ||
143 | module_param(dec_yuv_buffers, int, 0644); | ||
144 | module_param(dec_vbi_buffers, int, 0644); | ||
145 | |||
146 | module_param(newi2c, int, 0644); | ||
147 | |||
148 | MODULE_PARM_DESC(tuner, "Tuner type selection,\n" | ||
149 | "\t\t\tsee tuner.h for values"); | ||
150 | MODULE_PARM_DESC(radio, | ||
151 | "Enable or disable the radio. Use only if autodetection\n" | ||
152 | "\t\t\tfails. 0 = disable, 1 = enable"); | ||
153 | MODULE_PARM_DESC(cardtype, | ||
154 | "Only use this option if your card is not detected properly.\n" | ||
155 | "\t\tSpecify card type:\n" | ||
156 | "\t\t\t 1 = WinTV PVR 250\n" | ||
157 | "\t\t\t 2 = WinTV PVR 350\n" | ||
158 | "\t\t\t 3 = WinTV PVR-150 or PVR-500\n" | ||
159 | "\t\t\t 4 = AVerMedia M179\n" | ||
160 | "\t\t\t 5 = YUAN MPG600/Kuroutoshikou iTVC16-STVLP\n" | ||
161 | "\t\t\t 6 = YUAN MPG160/Kuroutoshikou iTVC15-STVLP\n" | ||
162 | "\t\t\t 7 = YUAN PG600/DIAMONDMM PVR-550 (CX Falcon 2)\n" | ||
163 | "\t\t\t 8 = Adaptec AVC-2410\n" | ||
164 | "\t\t\t 9 = Adaptec AVC-2010\n" | ||
165 | "\t\t\t10 = NAGASE TRANSGEAR 5000TV\n" | ||
166 | "\t\t\t11 = AOpen VA2000MAX-STN6\n" | ||
167 | "\t\t\t12 = YUAN MPG600GR/Kuroutoshikou CX23416GYC-STVLP\n" | ||
168 | "\t\t\t13 = I/O Data GV-MVP/RX\n" | ||
169 | "\t\t\t14 = I/O Data GV-MVP/RX2E\n" | ||
170 | "\t\t\t15 = GOTVIEW PCI DVD\n" | ||
171 | "\t\t\t16 = GOTVIEW PCI DVD2 Deluxe\n" | ||
172 | "\t\t\t17 = Yuan MPC622\n" | ||
173 | "\t\t\t18 = Digital Cowboy DCT-MTVP1\n" | ||
174 | #ifdef HAVE_XC3028 | ||
175 | "\t\t\t19 = Yuan PG600V2/GotView PCI DVD Lite/Club3D ZAP-TV1x01\n" | ||
176 | #endif | ||
177 | "\t\t\t 0 = Autodetect (default)\n" | ||
178 | "\t\t\t-1 = Ignore this card\n\t\t"); | ||
179 | MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60"); | ||
180 | MODULE_PARM_DESC(secam, "Set SECAM standard: B, G, H, D, K, L, LC"); | ||
181 | MODULE_PARM_DESC(ntsc, "Set NTSC standard: M, J, K"); | ||
182 | MODULE_PARM_DESC(debug, | ||
183 | "Debug level (bitmask). Default: errors only\n" | ||
184 | "\t\t\t(debug = 511 gives full debugging)"); | ||
185 | MODULE_PARM_DESC(ivtv_pci_latency, | ||
186 | "Change the PCI latency to 64 if lower: 0 = No, 1 = Yes,\n" | ||
187 | "\t\t\tDefault: Yes"); | ||
188 | MODULE_PARM_DESC(ivtv_yuv_mode, | ||
189 | "Specify the yuv playback mode:\n" | ||
190 | "\t\t\t0 = interlaced\n\t\t\t1 = progressive\n\t\t\t2 = auto\n" | ||
191 | "\t\t\tDefault: 0 (interlaced)"); | ||
192 | MODULE_PARM_DESC(ivtv_yuv_threshold, | ||
193 | "If ivtv_yuv_mode is 2 (auto) then playback content as\n\t\tprogressive if src height <= ivtv_yuvthreshold\n" | ||
194 | "\t\t\tDefault: 480");; | ||
195 | MODULE_PARM_DESC(enc_mpg_buffers, | ||
196 | "Encoder MPG Buffers (in MB)\n" | ||
197 | "\t\t\tDefault: " __stringify(IVTV_DEFAULT_ENC_MPG_BUFFERS)); | ||
198 | MODULE_PARM_DESC(enc_yuv_buffers, | ||
199 | "Encoder YUV Buffers (in MB)\n" | ||
200 | "\t\t\tDefault: " __stringify(IVTV_DEFAULT_ENC_YUV_BUFFERS)); | ||
201 | MODULE_PARM_DESC(enc_vbi_buffers, | ||
202 | "Encoder VBI Buffers (in MB)\n" | ||
203 | "\t\t\tDefault: " __stringify(IVTV_DEFAULT_ENC_VBI_BUFFERS)); | ||
204 | MODULE_PARM_DESC(enc_pcm_buffers, | ||
205 | "Encoder PCM buffers (in MB)\n" | ||
206 | "\t\t\tDefault: " __stringify(IVTV_DEFAULT_ENC_PCM_BUFFERS)); | ||
207 | MODULE_PARM_DESC(dec_mpg_buffers, | ||
208 | "Decoder MPG buffers (in MB)\n" | ||
209 | "\t\t\tDefault: " __stringify(IVTV_DEFAULT_DEC_MPG_BUFFERS)); | ||
210 | MODULE_PARM_DESC(dec_yuv_buffers, | ||
211 | "Decoder YUV buffers (in MB)\n" | ||
212 | "\t\t\tDefault: " __stringify(IVTV_DEFAULT_DEC_YUV_BUFFERS)); | ||
213 | MODULE_PARM_DESC(dec_vbi_buffers, | ||
214 | "Decoder VBI buffers (in MB)\n" | ||
215 | "\t\t\tDefault: " __stringify(IVTV_DEFAULT_DEC_VBI_BUFFERS)); | ||
216 | MODULE_PARM_DESC(newi2c, | ||
217 | "Use new I2C implementation\n" | ||
218 | "\t\t\t-1 is autodetect, 0 is off, 1 is on\n" | ||
219 | "\t\t\tDefault is autodetect"); | ||
220 | |||
221 | MODULE_PARM_DESC(ivtv_first_minor, "Set minor assigned to first card"); | ||
222 | |||
223 | MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil"); | ||
224 | MODULE_DESCRIPTION("CX23415/CX23416 driver"); | ||
225 | MODULE_SUPPORTED_DEVICE | ||
226 | ("CX23415/CX23416 MPEG2 encoder (WinTV PVR-150/250/350/500,\n" | ||
227 | "\t\t\tYuan MPG series and similar)"); | ||
228 | MODULE_LICENSE("GPL"); | ||
229 | |||
230 | MODULE_VERSION(IVTV_VERSION); | ||
231 | |||
232 | void ivtv_clear_irq_mask(struct ivtv *itv, u32 mask) | ||
233 | { | ||
234 | itv->irqmask &= ~mask; | ||
235 | write_reg_sync(itv->irqmask, IVTV_REG_IRQMASK); | ||
236 | } | ||
237 | |||
238 | void ivtv_set_irq_mask(struct ivtv *itv, u32 mask) | ||
239 | { | ||
240 | itv->irqmask |= mask; | ||
241 | write_reg_sync(itv->irqmask, IVTV_REG_IRQMASK); | ||
242 | } | ||
243 | |||
244 | int ivtv_set_output_mode(struct ivtv *itv, int mode) | ||
245 | { | ||
246 | int old_mode; | ||
247 | |||
248 | spin_lock(&itv->lock); | ||
249 | old_mode = itv->output_mode; | ||
250 | if (old_mode == 0) | ||
251 | itv->output_mode = old_mode = mode; | ||
252 | spin_unlock(&itv->lock); | ||
253 | return old_mode; | ||
254 | } | ||
255 | |||
256 | struct ivtv_stream *ivtv_get_output_stream(struct ivtv *itv) | ||
257 | { | ||
258 | switch (itv->output_mode) { | ||
259 | case OUT_MPG: | ||
260 | return &itv->streams[IVTV_DEC_STREAM_TYPE_MPG]; | ||
261 | case OUT_YUV: | ||
262 | return &itv->streams[IVTV_DEC_STREAM_TYPE_YUV]; | ||
263 | default: | ||
264 | return NULL; | ||
265 | } | ||
266 | } | ||
267 | |||
268 | int ivtv_waitq(wait_queue_head_t *waitq) | ||
269 | { | ||
270 | DEFINE_WAIT(wait); | ||
271 | |||
272 | prepare_to_wait(waitq, &wait, TASK_INTERRUPTIBLE); | ||
273 | schedule(); | ||
274 | finish_wait(waitq, &wait); | ||
275 | return signal_pending(current) ? -EINTR : 0; | ||
276 | } | ||
277 | |||
278 | /* Generic utility functions */ | ||
279 | int ivtv_sleep_timeout(int timeout, int intr) | ||
280 | { | ||
281 | int ret; | ||
282 | |||
283 | do { | ||
284 | set_current_state(intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); | ||
285 | timeout = schedule_timeout(timeout); | ||
286 | if (intr && (ret = signal_pending(current))) | ||
287 | return ret; | ||
288 | } while (timeout); | ||
289 | return 0; | ||
290 | } | ||
291 | |||
292 | /* Release ioremapped memory */ | ||
293 | static void ivtv_iounmap(struct ivtv *itv) | ||
294 | { | ||
295 | if (itv == NULL) | ||
296 | return; | ||
297 | |||
298 | /* Release registers memory */ | ||
299 | if (itv->reg_mem != NULL) { | ||
300 | IVTV_DEBUG_INFO("releasing reg_mem\n"); | ||
301 | iounmap(itv->reg_mem); | ||
302 | itv->reg_mem = NULL; | ||
303 | } | ||
304 | /* Release io memory */ | ||
305 | if (itv->has_cx23415 && itv->dec_mem != NULL) { | ||
306 | IVTV_DEBUG_INFO("releasing dec_mem\n"); | ||
307 | iounmap(itv->dec_mem); | ||
308 | } | ||
309 | itv->dec_mem = NULL; | ||
310 | |||
311 | /* Release io memory */ | ||
312 | if (itv->enc_mem != NULL) { | ||
313 | IVTV_DEBUG_INFO("releasing enc_mem\n"); | ||
314 | iounmap(itv->enc_mem); | ||
315 | itv->enc_mem = NULL; | ||
316 | } | ||
317 | } | ||
318 | |||
319 | /* Hauppauge card? get values from tveeprom */ | ||
320 | void ivtv_read_eeprom(struct ivtv *itv, struct tveeprom *tv) | ||
321 | { | ||
322 | u8 eedata[256]; | ||
323 | |||
324 | itv->i2c_client.addr = 0xA0 >> 1; | ||
325 | tveeprom_read(&itv->i2c_client, eedata, sizeof(eedata)); | ||
326 | tveeprom_hauppauge_analog(&itv->i2c_client, tv, eedata); | ||
327 | } | ||
328 | |||
329 | static void ivtv_process_eeprom(struct ivtv *itv) | ||
330 | { | ||
331 | struct tveeprom tv; | ||
332 | int pci_slot = PCI_SLOT(itv->dev->devfn); | ||
333 | |||
334 | ivtv_read_eeprom(itv, &tv); | ||
335 | |||
336 | /* Many thanks to Steven Toth from Hauppauge for providing the | ||
337 | model numbers */ | ||
338 | switch (tv.model) { | ||
339 | /* In a few cases the PCI subsystem IDs do not correctly | ||
340 | identify the card. A better method is to check the | ||
341 | model number from the eeprom instead. */ | ||
342 | case 32000 ... 32999: | ||
343 | case 48000 ... 48099: /* 48??? range are PVR250s with a cx23415 */ | ||
344 | case 48400 ... 48599: | ||
345 | itv->card = ivtv_get_card(IVTV_CARD_PVR_250); | ||
346 | break; | ||
347 | case 48100 ... 48399: | ||
348 | case 48600 ... 48999: | ||
349 | itv->card = ivtv_get_card(IVTV_CARD_PVR_350); | ||
350 | break; | ||
351 | case 23000 ... 23999: /* PVR500 */ | ||
352 | case 25000 ... 25999: /* Low profile PVR150 */ | ||
353 | case 26000 ... 26999: /* Regular PVR150 */ | ||
354 | itv->card = ivtv_get_card(IVTV_CARD_PVR_150); | ||
355 | break; | ||
356 | case 0: | ||
357 | IVTV_ERR("Invalid EEPROM\n"); | ||
358 | return; | ||
359 | default: | ||
360 | IVTV_ERR("Unknown model %d, defaulting to PVR-150\n", tv.model); | ||
361 | itv->card = ivtv_get_card(IVTV_CARD_PVR_150); | ||
362 | break; | ||
363 | } | ||
364 | |||
365 | switch (tv.model) { | ||
366 | /* Old style PVR350 (with an saa7114) uses this input for | ||
367 | the tuner. */ | ||
368 | case 48254: | ||
369 | itv->card = ivtv_get_card(IVTV_CARD_PVR_350_V1); | ||
370 | break; | ||
371 | default: | ||
372 | break; | ||
373 | } | ||
374 | |||
375 | itv->v4l2_cap = itv->card->v4l2_capabilities; | ||
376 | itv->card_name = itv->card->name; | ||
377 | |||
378 | /* If this is a PVR500 then it should be possible to detect whether it is the | ||
379 | first or second unit by looking at the subsystem device ID: is bit 4 is | ||
380 | set, then it is the second unit (according to info from Hauppauge). | ||
381 | |||
382 | However, while this works for most cards, I have seen a few PVR500 cards | ||
383 | where both units have the same subsystem ID. | ||
384 | |||
385 | So instead I look at the reported 'PCI slot' (which is the slot on the PVR500 | ||
386 | PCI bridge) and if it is 8, then it is assumed to be the first unit, otherwise | ||
387 | it is the second unit. It is possible that it is a different slot when ivtv is | ||
388 | used in Xen, in that case I ignore this card here. The worst that can happen | ||
389 | is that the card presents itself with a non-working radio device. | ||
390 | |||
391 | This detection is needed since the eeprom reports incorrectly that a radio is | ||
392 | present on the second unit. */ | ||
393 | if (tv.model / 1000 == 23) { | ||
394 | itv->card_name = "WinTV PVR 500"; | ||
395 | if (pci_slot == 8 || pci_slot == 9) { | ||
396 | int is_first = (pci_slot & 1) == 0; | ||
397 | |||
398 | itv->card_name = is_first ? "WinTV PVR 500 (unit #1)" : | ||
399 | "WinTV PVR 500 (unit #2)"; | ||
400 | if (!is_first) { | ||
401 | IVTV_INFO("Correcting tveeprom data: no radio present on second unit\n"); | ||
402 | tv.has_radio = 0; | ||
403 | } | ||
404 | } | ||
405 | } | ||
406 | IVTV_INFO("Autodetected %s\n", itv->card_name); | ||
407 | |||
408 | switch (tv.tuner_hauppauge_model) { | ||
409 | case 85: | ||
410 | case 99: | ||
411 | case 112: | ||
412 | itv->pvr150_workaround = 1; | ||
413 | break; | ||
414 | default: | ||
415 | break; | ||
416 | } | ||
417 | if (tv.tuner_type == TUNER_ABSENT) | ||
418 | IVTV_ERR("tveeprom cannot autodetect tuner!"); | ||
419 | |||
420 | if (itv->options.tuner == -1) | ||
421 | itv->options.tuner = tv.tuner_type; | ||
422 | if (itv->options.radio == -1) | ||
423 | itv->options.radio = (tv.has_radio != 0); | ||
424 | /* only enable newi2c if an IR blaster is present */ | ||
425 | /* FIXME: for 2.6.20 the test against 2 should be removed */ | ||
426 | if (itv->options.newi2c == -1 && tv.has_ir != -1 && tv.has_ir != 2) { | ||
427 | itv->options.newi2c = (tv.has_ir & 2) ? 1 : 0; | ||
428 | if (itv->options.newi2c) { | ||
429 | IVTV_INFO("reopen i2c bus for IR-blaster support\n"); | ||
430 | exit_ivtv_i2c(itv); | ||
431 | init_ivtv_i2c(itv); | ||
432 | } | ||
433 | } | ||
434 | |||
435 | if (itv->std != 0) | ||
436 | /* user specified tuner standard */ | ||
437 | return; | ||
438 | |||
439 | /* autodetect tuner standard */ | ||
440 | if (tv.tuner_formats & V4L2_STD_PAL) { | ||
441 | IVTV_DEBUG_INFO("PAL tuner detected\n"); | ||
442 | itv->std |= V4L2_STD_PAL_BG | V4L2_STD_PAL_H; | ||
443 | } else if (tv.tuner_formats & V4L2_STD_NTSC) { | ||
444 | IVTV_DEBUG_INFO("NTSC tuner detected\n"); | ||
445 | itv->std |= V4L2_STD_NTSC_M; | ||
446 | } else if (tv.tuner_formats & V4L2_STD_SECAM) { | ||
447 | IVTV_DEBUG_INFO("SECAM tuner detected\n"); | ||
448 | itv->std |= V4L2_STD_SECAM_L; | ||
449 | } else { | ||
450 | IVTV_INFO("No tuner detected, default to NTSC-M\n"); | ||
451 | itv->std |= V4L2_STD_NTSC_M; | ||
452 | } | ||
453 | } | ||
454 | |||
455 | static v4l2_std_id ivtv_parse_std(struct ivtv *itv) | ||
456 | { | ||
457 | switch (pal[0]) { | ||
458 | case '6': | ||
459 | return V4L2_STD_PAL_60; | ||
460 | case 'b': | ||
461 | case 'B': | ||
462 | case 'g': | ||
463 | case 'G': | ||
464 | return V4L2_STD_PAL_BG; | ||
465 | case 'h': | ||
466 | case 'H': | ||
467 | return V4L2_STD_PAL_H; | ||
468 | case 'n': | ||
469 | case 'N': | ||
470 | if (pal[1] == 'c' || pal[1] == 'C') | ||
471 | return V4L2_STD_PAL_Nc; | ||
472 | return V4L2_STD_PAL_N; | ||
473 | case 'i': | ||
474 | case 'I': | ||
475 | return V4L2_STD_PAL_I; | ||
476 | case 'd': | ||
477 | case 'D': | ||
478 | case 'k': | ||
479 | case 'K': | ||
480 | return V4L2_STD_PAL_DK; | ||
481 | case 'M': | ||
482 | case 'm': | ||
483 | return V4L2_STD_PAL_M; | ||
484 | case '-': | ||
485 | break; | ||
486 | default: | ||
487 | IVTV_WARN("pal= argument not recognised\n"); | ||
488 | return 0; | ||
489 | } | ||
490 | |||
491 | switch (secam[0]) { | ||
492 | case 'b': | ||
493 | case 'B': | ||
494 | case 'g': | ||
495 | case 'G': | ||
496 | case 'h': | ||
497 | case 'H': | ||
498 | return V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H; | ||
499 | case 'd': | ||
500 | case 'D': | ||
501 | case 'k': | ||
502 | case 'K': | ||
503 | return V4L2_STD_SECAM_DK; | ||
504 | case 'l': | ||
505 | case 'L': | ||
506 | if (secam[1] == 'C' || secam[1] == 'c') | ||
507 | return V4L2_STD_SECAM_LC; | ||
508 | return V4L2_STD_SECAM_L; | ||
509 | case '-': | ||
510 | break; | ||
511 | default: | ||
512 | IVTV_WARN("secam= argument not recognised\n"); | ||
513 | return 0; | ||
514 | } | ||
515 | |||
516 | switch (ntsc[0]) { | ||
517 | case 'm': | ||
518 | case 'M': | ||
519 | return V4L2_STD_NTSC_M; | ||
520 | case 'j': | ||
521 | case 'J': | ||
522 | return V4L2_STD_NTSC_M_JP; | ||
523 | case 'k': | ||
524 | case 'K': | ||
525 | return V4L2_STD_NTSC_M_KR; | ||
526 | case '-': | ||
527 | break; | ||
528 | default: | ||
529 | IVTV_WARN("ntsc= argument not recognised\n"); | ||
530 | return 0; | ||
531 | } | ||
532 | |||
533 | /* no match found */ | ||
534 | return 0; | ||
535 | } | ||
536 | |||
537 | static void ivtv_process_options(struct ivtv *itv) | ||
538 | { | ||
539 | const char *chipname; | ||
540 | int i, j; | ||
541 | |||
542 | itv->options.megabytes[IVTV_ENC_STREAM_TYPE_MPG] = enc_mpg_buffers; | ||
543 | itv->options.megabytes[IVTV_ENC_STREAM_TYPE_YUV] = enc_yuv_buffers; | ||
544 | itv->options.megabytes[IVTV_ENC_STREAM_TYPE_VBI] = enc_vbi_buffers; | ||
545 | itv->options.megabytes[IVTV_ENC_STREAM_TYPE_PCM] = enc_pcm_buffers; | ||
546 | itv->options.megabytes[IVTV_DEC_STREAM_TYPE_MPG] = dec_mpg_buffers; | ||
547 | itv->options.megabytes[IVTV_DEC_STREAM_TYPE_YUV] = dec_yuv_buffers; | ||
548 | itv->options.megabytes[IVTV_DEC_STREAM_TYPE_VBI] = dec_vbi_buffers; | ||
549 | itv->options.cardtype = cardtype[itv->num]; | ||
550 | itv->options.tuner = tuner[itv->num]; | ||
551 | itv->options.radio = radio[itv->num]; | ||
552 | itv->options.newi2c = newi2c; | ||
553 | |||
554 | itv->std = ivtv_parse_std(itv); | ||
555 | itv->has_cx23415 = (itv->dev->device == PCI_DEVICE_ID_IVTV15); | ||
556 | chipname = itv->has_cx23415 ? "cx23415" : "cx23416"; | ||
557 | if (itv->options.cardtype == -1) { | ||
558 | IVTV_INFO("Ignore card (detected %s based chip)\n", chipname); | ||
559 | return; | ||
560 | } | ||
561 | if ((itv->card = ivtv_get_card(itv->options.cardtype - 1))) { | ||
562 | IVTV_INFO("User specified %s card (detected %s based chip)\n", | ||
563 | itv->card->name, chipname); | ||
564 | } else if (itv->options.cardtype != 0) { | ||
565 | IVTV_ERR("Unknown user specified type, trying to autodetect card\n"); | ||
566 | } | ||
567 | if (itv->card == NULL) { | ||
568 | if (itv->dev->subsystem_vendor == IVTV_PCI_ID_HAUPPAUGE || | ||
569 | itv->dev->subsystem_vendor == IVTV_PCI_ID_HAUPPAUGE_ALT1 || | ||
570 | itv->dev->subsystem_vendor == IVTV_PCI_ID_HAUPPAUGE_ALT2) { | ||
571 | itv->card = ivtv_get_card(itv->has_cx23415 ? IVTV_CARD_PVR_350 : IVTV_CARD_PVR_150); | ||
572 | IVTV_INFO("Autodetected Hauppauge card (%s based)\n", | ||
573 | chipname); | ||
574 | } | ||
575 | } | ||
576 | if (itv->card == NULL) { | ||
577 | for (i = 0; (itv->card = ivtv_get_card(i)); i++) { | ||
578 | if (itv->card->pci_list == NULL) | ||
579 | continue; | ||
580 | for (j = 0; itv->card->pci_list[j].device; j++) { | ||
581 | if (itv->dev->device != | ||
582 | itv->card->pci_list[j].device) | ||
583 | continue; | ||
584 | if (itv->dev->subsystem_vendor != | ||
585 | itv->card->pci_list[j].subsystem_vendor) | ||
586 | continue; | ||
587 | if (itv->dev->subsystem_device != | ||
588 | itv->card->pci_list[j].subsystem_device) | ||
589 | continue; | ||
590 | IVTV_INFO("Autodetected %s card (%s based)\n", | ||
591 | itv->card->name, chipname); | ||
592 | goto done; | ||
593 | } | ||
594 | } | ||
595 | } | ||
596 | done: | ||
597 | |||
598 | if (itv->card == NULL) { | ||
599 | itv->card = ivtv_get_card(IVTV_CARD_PVR_150); | ||
600 | IVTV_ERR("Unknown card: vendor/device: %04x/%04x\n", | ||
601 | itv->dev->vendor, itv->dev->device); | ||
602 | IVTV_ERR(" subsystem vendor/device: %04x/%04x\n", | ||
603 | itv->dev->subsystem_vendor, itv->dev->subsystem_device); | ||
604 | IVTV_ERR(" %s based\n", chipname); | ||
605 | IVTV_ERR("Defaulting to %s card\n", itv->card->name); | ||
606 | IVTV_ERR("Please mail the vendor/device and subsystem vendor/device IDs and what kind of\n"); | ||
607 | IVTV_ERR("card you have to the ivtv-devel mailinglist (www.ivtvdriver.org)\n"); | ||
608 | IVTV_ERR("Prefix your subject line with [UNKNOWN CARD].\n"); | ||
609 | } | ||
610 | itv->v4l2_cap = itv->card->v4l2_capabilities; | ||
611 | itv->card_name = itv->card->name; | ||
612 | } | ||
613 | |||
614 | /* Precondition: the ivtv structure has been memset to 0. Only | ||
615 | the dev and num fields have been filled in. | ||
616 | No assumptions on the card type may be made here (see ivtv_init_struct2 | ||
617 | for that). | ||
618 | */ | ||
619 | static int __devinit ivtv_init_struct1(struct ivtv *itv) | ||
620 | { | ||
621 | itv->base_addr = pci_resource_start(itv->dev, 0); | ||
622 | itv->enc_mbox.max_mbox = 2; /* the encoder has 3 mailboxes (0-2) */ | ||
623 | itv->dec_mbox.max_mbox = 1; /* the decoder has 2 mailboxes (0-1) */ | ||
624 | |||
625 | mutex_init(&itv->i2c_bus_lock); | ||
626 | mutex_init(&itv->udma.lock); | ||
627 | |||
628 | spin_lock_init(&itv->lock); | ||
629 | spin_lock_init(&itv->dma_reg_lock); | ||
630 | |||
631 | itv->irq_work_queues = create_workqueue(itv->name); | ||
632 | if (itv->irq_work_queues == NULL) { | ||
633 | IVTV_ERR("Could not create ivtv workqueue\n"); | ||
634 | return -1; | ||
635 | } | ||
636 | |||
637 | INIT_WORK(&itv->irq_work_queue, ivtv_irq_work_handler); | ||
638 | |||
639 | /* start counting open_id at 1 */ | ||
640 | itv->open_id = 1; | ||
641 | |||
642 | /* Initial settings */ | ||
643 | cx2341x_fill_defaults(&itv->params); | ||
644 | itv->params.port = CX2341X_PORT_MEMORY; | ||
645 | itv->params.capabilities = CX2341X_CAP_HAS_SLICED_VBI; | ||
646 | init_waitqueue_head(&itv->cap_w); | ||
647 | init_waitqueue_head(&itv->event_waitq); | ||
648 | init_waitqueue_head(&itv->vsync_waitq); | ||
649 | init_waitqueue_head(&itv->dma_waitq); | ||
650 | init_timer(&itv->dma_timer); | ||
651 | itv->dma_timer.function = ivtv_unfinished_dma; | ||
652 | itv->dma_timer.data = (unsigned long)itv; | ||
653 | |||
654 | itv->cur_dma_stream = -1; | ||
655 | itv->audio_stereo_mode = AUDIO_STEREO; | ||
656 | itv->audio_bilingual_mode = AUDIO_MONO_LEFT; | ||
657 | |||
658 | /* Ctrls */ | ||
659 | itv->speed = 1000; | ||
660 | |||
661 | /* VBI */ | ||
662 | itv->vbi.in.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE; | ||
663 | itv->vbi.sliced_in = &itv->vbi.in.fmt.sliced; | ||
664 | |||
665 | /* OSD */ | ||
666 | itv->osd_global_alpha_state = 1; | ||
667 | itv->osd_global_alpha = 255; | ||
668 | |||
669 | /* YUV */ | ||
670 | atomic_set(&itv->yuv_info.next_dma_frame, -1); | ||
671 | itv->yuv_info.lace_mode = ivtv_yuv_mode; | ||
672 | itv->yuv_info.lace_threshold = ivtv_yuv_threshold; | ||
673 | return 0; | ||
674 | } | ||
675 | |||
676 | /* Second initialization part. Here the card type has been | ||
677 | autodetected. */ | ||
678 | static void __devinit ivtv_init_struct2(struct ivtv *itv) | ||
679 | { | ||
680 | int i; | ||
681 | |||
682 | for (i = 0; i < IVTV_CARD_MAX_VIDEO_INPUTS; i++) | ||
683 | if (itv->card->video_inputs[i].video_type == 0) | ||
684 | break; | ||
685 | itv->nof_inputs = i; | ||
686 | for (i = 0; i < IVTV_CARD_MAX_AUDIO_INPUTS; i++) | ||
687 | if (itv->card->audio_inputs[i].audio_type == 0) | ||
688 | break; | ||
689 | itv->nof_audio_inputs = i; | ||
690 | |||
691 | /* 0x00EF = saa7114(239) 0x00F0 = saa7115(240) 0x0106 = micro */ | ||
692 | if (itv->card->hw_all & (IVTV_HW_SAA7115 | IVTV_HW_SAA717X)) | ||
693 | itv->digitizer = 0xF1; | ||
694 | else if (itv->card->hw_all & IVTV_HW_SAA7114) | ||
695 | itv->digitizer = 0xEF; | ||
696 | else /* cx25840 */ | ||
697 | itv->digitizer = 0x140; | ||
698 | |||
699 | if (itv->card->hw_all & IVTV_HW_CX25840) { | ||
700 | itv->vbi.sliced_size = 288; /* multiple of 16, real size = 284 */ | ||
701 | } else { | ||
702 | itv->vbi.sliced_size = 64; /* multiple of 16, real size = 52 */ | ||
703 | } | ||
704 | |||
705 | /* Find tuner input */ | ||
706 | for (i = 0; i < itv->nof_inputs; i++) { | ||
707 | if (itv->card->video_inputs[i].video_type == | ||
708 | IVTV_CARD_INPUT_VID_TUNER) | ||
709 | break; | ||
710 | } | ||
711 | if (i == itv->nof_inputs) | ||
712 | i = 0; | ||
713 | itv->active_input = i; | ||
714 | itv->audio_input = itv->card->video_inputs[i].audio_index; | ||
715 | if (itv->card->hw_all & IVTV_HW_CX25840) | ||
716 | itv->video_dec_func = ivtv_cx25840; | ||
717 | else if (itv->card->hw_all & IVTV_HW_SAA717X) | ||
718 | itv->video_dec_func = ivtv_saa717x; | ||
719 | else | ||
720 | itv->video_dec_func = ivtv_saa7115; | ||
721 | } | ||
722 | |||
723 | static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *dev, | ||
724 | const struct pci_device_id *pci_id) | ||
725 | { | ||
726 | u16 cmd; | ||
727 | unsigned char pci_latency; | ||
728 | |||
729 | IVTV_DEBUG_INFO("Enabling pci device\n"); | ||
730 | |||
731 | if (pci_enable_device(dev)) { | ||
732 | IVTV_ERR("Can't enable device %d!\n", itv->num); | ||
733 | return -EIO; | ||
734 | } | ||
735 | if (pci_set_dma_mask(dev, 0xffffffff)) { | ||
736 | IVTV_ERR("No suitable DMA available on card %d.\n", itv->num); | ||
737 | return -EIO; | ||
738 | } | ||
739 | if (!request_mem_region(itv->base_addr, IVTV_ENCODER_SIZE, "ivtv encoder")) { | ||
740 | IVTV_ERR("Cannot request encoder memory region on card %d.\n", itv->num); | ||
741 | return -EIO; | ||
742 | } | ||
743 | |||
744 | if (!request_mem_region(itv->base_addr + IVTV_REG_OFFSET, | ||
745 | IVTV_REG_SIZE, "ivtv registers")) { | ||
746 | IVTV_ERR("Cannot request register memory region on card %d.\n", itv->num); | ||
747 | release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE); | ||
748 | return -EIO; | ||
749 | } | ||
750 | |||
751 | if (itv->has_cx23415 && | ||
752 | !request_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, | ||
753 | IVTV_DECODER_SIZE, "ivtv decoder")) { | ||
754 | IVTV_ERR("Cannot request decoder memory region on card %d.\n", itv->num); | ||
755 | release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE); | ||
756 | release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE); | ||
757 | return -EIO; | ||
758 | } | ||
759 | |||
760 | /* Check for bus mastering */ | ||
761 | pci_read_config_word(dev, PCI_COMMAND, &cmd); | ||
762 | if (!(cmd & PCI_COMMAND_MASTER)) { | ||
763 | IVTV_DEBUG_INFO("Attempting to enable Bus Mastering\n"); | ||
764 | pci_set_master(dev); | ||
765 | pci_read_config_word(dev, PCI_COMMAND, &cmd); | ||
766 | if (!(cmd & PCI_COMMAND_MASTER)) { | ||
767 | IVTV_ERR("Bus Mastering is not enabled\n"); | ||
768 | return -ENXIO; | ||
769 | } | ||
770 | } | ||
771 | IVTV_DEBUG_INFO("Bus Mastering Enabled.\n"); | ||
772 | |||
773 | pci_read_config_byte(dev, PCI_CLASS_REVISION, &itv->card_rev); | ||
774 | pci_read_config_byte(dev, PCI_LATENCY_TIMER, &pci_latency); | ||
775 | |||
776 | if (pci_latency < 64 && ivtv_pci_latency) { | ||
777 | IVTV_INFO("Unreasonably low latency timer, " | ||
778 | "setting to 64 (was %d)\n", pci_latency); | ||
779 | pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64); | ||
780 | pci_read_config_byte(dev, PCI_LATENCY_TIMER, &pci_latency); | ||
781 | } | ||
782 | /* This config space value relates to DMA latencies. The | ||
783 | default value 0x8080 is too low however and will lead | ||
784 | to DMA errors. 0xffff is the max value which solves | ||
785 | these problems. */ | ||
786 | pci_write_config_dword(dev, 0x40, 0xffff); | ||
787 | |||
788 | IVTV_DEBUG_INFO("%d (rev %d) at %02x:%02x.%x, " | ||
789 | "irq: %d, latency: %d, memory: 0x%lx\n", | ||
790 | itv->dev->device, itv->card_rev, dev->bus->number, | ||
791 | PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), | ||
792 | itv->dev->irq, pci_latency, (unsigned long)itv->base_addr); | ||
793 | |||
794 | return 0; | ||
795 | } | ||
796 | |||
797 | static void ivtv_request_module(struct ivtv *itv, const char *name) | ||
798 | { | ||
799 | if (request_module(name) != 0) { | ||
800 | IVTV_ERR("Failed to load module %s\n", name); | ||
801 | } else { | ||
802 | IVTV_DEBUG_INFO("Loaded module %s\n", name); | ||
803 | } | ||
804 | } | ||
805 | |||
806 | static void ivtv_load_and_init_modules(struct ivtv *itv) | ||
807 | { | ||
808 | struct v4l2_control ctrl; | ||
809 | u32 hw = itv->card->hw_all; | ||
810 | int i; | ||
811 | |||
812 | /* load modules */ | ||
813 | #ifndef CONFIG_VIDEO_TUNER | ||
814 | if (hw & IVTV_HW_TUNER) { | ||
815 | ivtv_request_module(itv, "tuner"); | ||
816 | #ifdef HAVE_XC3028 | ||
817 | if (itv->options.tuner == TUNER_XCEIVE_XC3028) | ||
818 | ivtv_request_module(itv, "xc3028-tuner"); | ||
819 | #endif | ||
820 | } | ||
821 | #endif | ||
822 | #ifndef CONFIG_VIDEO_CX25840 | ||
823 | if (hw & IVTV_HW_CX25840) | ||
824 | ivtv_request_module(itv, "cx25840"); | ||
825 | #endif | ||
826 | #ifndef CONFIG_VIDEO_SAA711X | ||
827 | if (hw & IVTV_HW_SAA711X) | ||
828 | ivtv_request_module(itv, "saa7115"); | ||
829 | #endif | ||
830 | #ifndef CONFIG_VIDEO_SAA7127 | ||
831 | if (hw & IVTV_HW_SAA7127) | ||
832 | ivtv_request_module(itv, "saa7127"); | ||
833 | #endif | ||
834 | if (hw & IVTV_HW_SAA717X) | ||
835 | ivtv_request_module(itv, "saa717x"); | ||
836 | #ifndef CONFIG_VIDEO_UPD64031A | ||
837 | if (hw & IVTV_HW_UPD64031A) | ||
838 | ivtv_request_module(itv, "upd64031a"); | ||
839 | #endif | ||
840 | #ifndef CONFIG_VIDEO_UPD64083 | ||
841 | if (hw & IVTV_HW_UPD6408X) | ||
842 | ivtv_request_module(itv, "upd64083"); | ||
843 | #endif | ||
844 | #ifndef CONFIG_VIDEO_MSP3400 | ||
845 | if (hw & IVTV_HW_MSP34XX) | ||
846 | ivtv_request_module(itv, "msp3400"); | ||
847 | #endif | ||
848 | if (hw & IVTV_HW_TVAUDIO) | ||
849 | ivtv_request_module(itv, "tvaudio"); | ||
850 | #ifndef CONFIG_VIDEO_WM8775 | ||
851 | if (hw & IVTV_HW_WM8775) | ||
852 | ivtv_request_module(itv, "wm8775"); | ||
853 | #endif | ||
854 | #ifndef CONFIG_VIDEO_WM8739 | ||
855 | if (hw & IVTV_HW_WM8739) | ||
856 | ivtv_request_module(itv, "wm8739"); | ||
857 | #endif | ||
858 | #ifndef CONFIG_VIDEO_CS53L32A | ||
859 | if (hw & IVTV_HW_CS53L32A) | ||
860 | ivtv_request_module(itv, "cs53l32a"); | ||
861 | #endif | ||
862 | |||
863 | /* check which i2c devices are actually found */ | ||
864 | for (i = 0; i < 32; i++) { | ||
865 | u32 device = 1 << i; | ||
866 | |||
867 | if (!(device & hw)) | ||
868 | continue; | ||
869 | if (device == IVTV_HW_GPIO) { | ||
870 | /* GPIO is always available */ | ||
871 | itv->hw_flags |= IVTV_HW_GPIO; | ||
872 | continue; | ||
873 | } | ||
874 | if (ivtv_i2c_hw_addr(itv, device) > 0) | ||
875 | itv->hw_flags |= device; | ||
876 | } | ||
877 | |||
878 | hw = itv->hw_flags; | ||
879 | |||
880 | if (itv->card->type == IVTV_CARD_CX23416GYC) { | ||
881 | /* Several variations of this card exist, detect which card | ||
882 | type should be used. */ | ||
883 | if ((hw & (IVTV_HW_UPD64031A | IVTV_HW_UPD6408X)) == 0) | ||
884 | itv->card = ivtv_get_card(IVTV_CARD_CX23416GYC_NOGRYCS); | ||
885 | else if ((hw & IVTV_HW_UPD64031A) == 0) | ||
886 | itv->card = ivtv_get_card(IVTV_CARD_CX23416GYC_NOGR); | ||
887 | } | ||
888 | |||
889 | if (hw & IVTV_HW_CX25840) { | ||
890 | /* CX25840_CID_ENABLE_PVR150_WORKAROUND */ | ||
891 | ctrl.id = V4L2_CID_PRIVATE_BASE; | ||
892 | ctrl.value = itv->pvr150_workaround; | ||
893 | itv->video_dec_func(itv, VIDIOC_S_CTRL, &ctrl); | ||
894 | |||
895 | itv->vbi.raw_decoder_line_size = 1444; | ||
896 | itv->vbi.raw_decoder_sav_odd_field = 0x20; | ||
897 | itv->vbi.raw_decoder_sav_even_field = 0x60; | ||
898 | itv->vbi.sliced_decoder_line_size = 272; | ||
899 | itv->vbi.sliced_decoder_sav_odd_field = 0xB0; | ||
900 | itv->vbi.sliced_decoder_sav_even_field = 0xF0; | ||
901 | } | ||
902 | |||
903 | if (hw & IVTV_HW_SAA711X) { | ||
904 | struct v4l2_chip_ident v = { V4L2_CHIP_MATCH_I2C_DRIVER, I2C_DRIVERID_SAA711X }; | ||
905 | |||
906 | /* determine the exact saa711x model */ | ||
907 | itv->hw_flags &= ~IVTV_HW_SAA711X; | ||
908 | |||
909 | ivtv_saa7115(itv, VIDIOC_G_CHIP_IDENT, &v); | ||
910 | if (v.ident == V4L2_IDENT_SAA7114) { | ||
911 | itv->hw_flags |= IVTV_HW_SAA7114; | ||
912 | /* VBI is not yet supported by the saa7114 driver. */ | ||
913 | itv->v4l2_cap &= ~(V4L2_CAP_SLICED_VBI_CAPTURE|V4L2_CAP_VBI_CAPTURE); | ||
914 | } | ||
915 | else { | ||
916 | itv->hw_flags |= IVTV_HW_SAA7115; | ||
917 | } | ||
918 | itv->vbi.raw_decoder_line_size = 1443; | ||
919 | itv->vbi.raw_decoder_sav_odd_field = 0x25; | ||
920 | itv->vbi.raw_decoder_sav_even_field = 0x62; | ||
921 | itv->vbi.sliced_decoder_line_size = 51; | ||
922 | itv->vbi.sliced_decoder_sav_odd_field = 0xAB; | ||
923 | itv->vbi.sliced_decoder_sav_even_field = 0xEC; | ||
924 | } | ||
925 | |||
926 | if (hw & IVTV_HW_SAA717X) { | ||
927 | itv->vbi.raw_decoder_line_size = 1443; | ||
928 | itv->vbi.raw_decoder_sav_odd_field = 0x25; | ||
929 | itv->vbi.raw_decoder_sav_even_field = 0x62; | ||
930 | itv->vbi.sliced_decoder_line_size = 51; | ||
931 | itv->vbi.sliced_decoder_sav_odd_field = 0xAB; | ||
932 | itv->vbi.sliced_decoder_sav_even_field = 0xEC; | ||
933 | } | ||
934 | } | ||
935 | |||
936 | static int __devinit ivtv_probe(struct pci_dev *dev, | ||
937 | const struct pci_device_id *pci_id) | ||
938 | { | ||
939 | int retval = 0; | ||
940 | int video_input; | ||
941 | int yuv_buf_size; | ||
942 | int vbi_buf_size; | ||
943 | int fw_retry_count = 3; | ||
944 | struct ivtv *itv; | ||
945 | struct v4l2_frequency vf; | ||
946 | |||
947 | spin_lock(&ivtv_cards_lock); | ||
948 | |||
949 | /* Make sure we've got a place for this card */ | ||
950 | if (ivtv_cards_active == IVTV_MAX_CARDS) { | ||
951 | printk(KERN_ERR "ivtv: Maximum number of cards detected (%d).\n", | ||
952 | ivtv_cards_active); | ||
953 | spin_unlock(&ivtv_cards_lock); | ||
954 | return -ENOMEM; | ||
955 | } | ||
956 | |||
957 | itv = kzalloc(sizeof(struct ivtv), GFP_ATOMIC); | ||
958 | if (itv == 0) { | ||
959 | spin_unlock(&ivtv_cards_lock); | ||
960 | return -ENOMEM; | ||
961 | } | ||
962 | ivtv_cards[ivtv_cards_active] = itv; | ||
963 | itv->dev = dev; | ||
964 | itv->num = ivtv_cards_active++; | ||
965 | snprintf(itv->name, sizeof(itv->name) - 1, "ivtv%d", itv->num); | ||
966 | if (itv->num) { | ||
967 | printk(KERN_INFO "ivtv: ====================== NEXT CARD ======================\n"); | ||
968 | } | ||
969 | |||
970 | spin_unlock(&ivtv_cards_lock); | ||
971 | |||
972 | ivtv_process_options(itv); | ||
973 | if (itv->options.cardtype == -1) { | ||
974 | retval = -ENODEV; | ||
975 | goto err; | ||
976 | } | ||
977 | if (ivtv_init_struct1(itv)) { | ||
978 | retval = -ENOMEM; | ||
979 | goto err; | ||
980 | } | ||
981 | |||
982 | IVTV_DEBUG_INFO("base addr: 0x%08x\n", itv->base_addr); | ||
983 | |||
984 | /* PCI Device Setup */ | ||
985 | if ((retval = ivtv_setup_pci(itv, dev, pci_id)) != 0) { | ||
986 | if (retval == -EIO) | ||
987 | goto free_workqueue; | ||
988 | else if (retval == -ENXIO) | ||
989 | goto free_mem; | ||
990 | } | ||
991 | /* save itv in the pci struct for later use */ | ||
992 | pci_set_drvdata(dev, itv); | ||
993 | |||
994 | /* map io memory */ | ||
995 | IVTV_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n", | ||
996 | itv->base_addr + IVTV_ENCODER_OFFSET, IVTV_ENCODER_SIZE); | ||
997 | itv->enc_mem = ioremap_nocache(itv->base_addr + IVTV_ENCODER_OFFSET, | ||
998 | IVTV_ENCODER_SIZE); | ||
999 | if (!itv->enc_mem) { | ||
1000 | IVTV_ERR("ioremap failed, perhaps increasing __VMALLOC_RESERVE in page.h\n"); | ||
1001 | IVTV_ERR("or disabling CONFIG_HIMEM4G into the kernel would help\n"); | ||
1002 | retval = -ENOMEM; | ||
1003 | goto free_mem; | ||
1004 | } | ||
1005 | |||
1006 | if (itv->has_cx23415) { | ||
1007 | IVTV_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n", | ||
1008 | itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE); | ||
1009 | itv->dec_mem = ioremap_nocache(itv->base_addr + IVTV_DECODER_OFFSET, | ||
1010 | IVTV_DECODER_SIZE); | ||
1011 | if (!itv->dec_mem) { | ||
1012 | IVTV_ERR("ioremap failed, perhaps increasing __VMALLOC_RESERVE in page.h\n"); | ||
1013 | IVTV_ERR("or disabling CONFIG_HIMEM4G into the kernel would help\n"); | ||
1014 | retval = -ENOMEM; | ||
1015 | goto free_mem; | ||
1016 | } | ||
1017 | } | ||
1018 | else { | ||
1019 | itv->dec_mem = itv->enc_mem; | ||
1020 | } | ||
1021 | |||
1022 | /* map registers memory */ | ||
1023 | IVTV_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n", | ||
1024 | itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE); | ||
1025 | itv->reg_mem = | ||
1026 | ioremap_nocache(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE); | ||
1027 | if (!itv->reg_mem) { | ||
1028 | IVTV_ERR("ioremap failed, perhaps increasing __VMALLOC_RESERVE in page.h\n"); | ||
1029 | IVTV_ERR("or disabling CONFIG_HIMEM4G into the kernel would help\n"); | ||
1030 | retval = -ENOMEM; | ||
1031 | goto free_io; | ||
1032 | } | ||
1033 | |||
1034 | while (--fw_retry_count > 0) { | ||
1035 | /* load firmware */ | ||
1036 | if (ivtv_firmware_init(itv) == 0) | ||
1037 | break; | ||
1038 | if (fw_retry_count > 1) | ||
1039 | IVTV_WARN("Retry loading firmware\n"); | ||
1040 | } | ||
1041 | if (fw_retry_count == 0) { | ||
1042 | IVTV_ERR("Error initializing firmware\n"); | ||
1043 | goto free_i2c; | ||
1044 | } | ||
1045 | |||
1046 | /* Try and get firmware versions */ | ||
1047 | IVTV_DEBUG_INFO("Getting firmware version..\n"); | ||
1048 | ivtv_firmware_versions(itv); | ||
1049 | |||
1050 | /* Check yuv output filter table */ | ||
1051 | if (itv->has_cx23415) ivtv_yuv_filter_check(itv); | ||
1052 | |||
1053 | ivtv_gpio_init(itv); | ||
1054 | |||
1055 | /* active i2c */ | ||
1056 | IVTV_DEBUG_INFO("activating i2c...\n"); | ||
1057 | if (init_ivtv_i2c(itv)) { | ||
1058 | IVTV_ERR("Could not initialize i2c\n"); | ||
1059 | goto free_irq; | ||
1060 | } | ||
1061 | |||
1062 | IVTV_DEBUG_INFO("Active card count: %d.\n", ivtv_cards_active); | ||
1063 | |||
1064 | if (itv->card->hw_all & IVTV_HW_TVEEPROM) { | ||
1065 | #ifdef CONFIG_VIDEO_TVEEPROM_MODULE | ||
1066 | ivtv_request_module(itv, "tveeprom"); | ||
1067 | #endif | ||
1068 | /* Based on the model number the cardtype may be changed. | ||
1069 | The PCI IDs are not always reliable. */ | ||
1070 | ivtv_process_eeprom(itv); | ||
1071 | } | ||
1072 | |||
1073 | if (itv->std == 0) { | ||
1074 | itv->std = V4L2_STD_NTSC_M; | ||
1075 | } | ||
1076 | |||
1077 | if (itv->options.tuner == -1) { | ||
1078 | int i; | ||
1079 | |||
1080 | for (i = 0; i < IVTV_CARD_MAX_TUNERS; i++) { | ||
1081 | if ((itv->std & itv->card->tuners[i].std) == 0) | ||
1082 | continue; | ||
1083 | itv->options.tuner = itv->card->tuners[i].tuner; | ||
1084 | break; | ||
1085 | } | ||
1086 | } | ||
1087 | /* if no tuner was found, then pick the first tuner in the card list */ | ||
1088 | if (itv->options.tuner == -1 && itv->card->tuners[0].std) { | ||
1089 | itv->std = itv->card->tuners[0].std; | ||
1090 | itv->options.tuner = itv->card->tuners[0].tuner; | ||
1091 | } | ||
1092 | if (itv->options.radio == -1) | ||
1093 | itv->options.radio = (itv->card->radio_input.audio_type != 0); | ||
1094 | |||
1095 | /* The card is now fully identified, continue with card-specific | ||
1096 | initialization. */ | ||
1097 | ivtv_init_struct2(itv); | ||
1098 | |||
1099 | ivtv_load_and_init_modules(itv); | ||
1100 | |||
1101 | if (itv->std & V4L2_STD_525_60) { | ||
1102 | itv->is_60hz = 1; | ||
1103 | itv->is_out_60hz = 1; | ||
1104 | } else { | ||
1105 | itv->is_50hz = 1; | ||
1106 | itv->is_out_50hz = 1; | ||
1107 | } | ||
1108 | itv->params.video_gop_size = itv->is_60hz ? 15 : 12; | ||
1109 | |||
1110 | itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_MPG] = 0x08000; | ||
1111 | itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_PCM] = 0x01200; | ||
1112 | itv->stream_buf_size[IVTV_DEC_STREAM_TYPE_MPG] = 0x10000; | ||
1113 | |||
1114 | /* 0x15180 == 720 * 480 / 4, 0x19500 == 720 * 576 / 4 */ | ||
1115 | yuv_buf_size = itv->is_60hz ? 0x15180 : 0x19500; | ||
1116 | itv->stream_buf_size[IVTV_DEC_STREAM_TYPE_YUV] = yuv_buf_size / 2; | ||
1117 | itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_YUV] = yuv_buf_size / 8; | ||
1118 | |||
1119 | /* Setup VBI Raw Size. Should be big enough to hold PAL. | ||
1120 | It is possible to switch between PAL and NTSC, so we need to | ||
1121 | take the largest size here. */ | ||
1122 | /* 1456 is multiple of 16, real size = 1444 */ | ||
1123 | itv->vbi.raw_size = 1456; | ||
1124 | /* We use a buffer size of 1/2 of the total size needed for a | ||
1125 | frame. This is actually very useful, since we now receive | ||
1126 | a field at a time and that makes 'compressing' the raw data | ||
1127 | down to size by stripping off the SAV codes a lot easier. | ||
1128 | Note: having two different buffer sizes prevents standard | ||
1129 | switching on the fly. We need to find a better solution... */ | ||
1130 | vbi_buf_size = itv->vbi.raw_size * (itv->is_60hz ? 24 : 36) / 2; | ||
1131 | itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_VBI] = vbi_buf_size; | ||
1132 | itv->stream_buf_size[IVTV_DEC_STREAM_TYPE_VBI] = sizeof(struct v4l2_sliced_vbi_data) * 36; | ||
1133 | |||
1134 | if (itv->options.radio > 0) | ||
1135 | itv->v4l2_cap |= V4L2_CAP_RADIO; | ||
1136 | |||
1137 | if (itv->options.tuner > -1) { | ||
1138 | struct tuner_setup setup; | ||
1139 | |||
1140 | setup.addr = ADDR_UNSET; | ||
1141 | setup.type = itv->options.tuner; | ||
1142 | setup.mode_mask = T_ANALOG_TV; /* matches TV tuners */ | ||
1143 | #ifdef HAVE_XC3028 | ||
1144 | setup.initmode = V4L2_TUNER_ANALOG_TV; | ||
1145 | if (itv->options.tuner == TUNER_XCEIVE_XC3028) { | ||
1146 | setup.gpio_write = ivtv_reset_tuner_gpio; | ||
1147 | setup.gpio_priv = itv; | ||
1148 | } | ||
1149 | #endif | ||
1150 | ivtv_call_i2c_clients(itv, TUNER_SET_TYPE_ADDR, &setup); | ||
1151 | } | ||
1152 | |||
1153 | vf.tuner = 0; | ||
1154 | vf.type = V4L2_TUNER_ANALOG_TV; | ||
1155 | vf.frequency = 6400; /* the tuner 'baseline' frequency */ | ||
1156 | if (itv->std & V4L2_STD_NTSC_M) { | ||
1157 | /* Why on earth? */ | ||
1158 | vf.frequency = 1076; /* ch. 4 67250*16/1000 */ | ||
1159 | } | ||
1160 | |||
1161 | /* The tuner is fixed to the standard. The other inputs (e.g. S-Video) | ||
1162 | are not. */ | ||
1163 | itv->tuner_std = itv->std; | ||
1164 | |||
1165 | video_input = itv->active_input; | ||
1166 | itv->active_input++; /* Force update of input */ | ||
1167 | ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_INPUT, &video_input); | ||
1168 | |||
1169 | /* Let the VIDIOC_S_STD ioctl do all the work, keeps the code | ||
1170 | in one place. */ | ||
1171 | itv->std++; /* Force full standard initialization */ | ||
1172 | itv->std_out = itv->std; | ||
1173 | ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_FREQUENCY, &vf); | ||
1174 | |||
1175 | retval = ivtv_streams_setup(itv); | ||
1176 | if (retval) { | ||
1177 | IVTV_ERR("Error %d setting up streams\n", retval); | ||
1178 | goto free_i2c; | ||
1179 | } | ||
1180 | |||
1181 | if (itv->card->v4l2_capabilities & V4L2_CAP_VIDEO_OUTPUT) { | ||
1182 | ivtv_init_mpeg_decoder(itv); | ||
1183 | } | ||
1184 | ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_STD, &itv->tuner_std); | ||
1185 | |||
1186 | IVTV_DEBUG_IRQ("Masking interrupts\n"); | ||
1187 | /* clear interrupt mask, effectively disabling interrupts */ | ||
1188 | ivtv_set_irq_mask(itv, 0xffffffff); | ||
1189 | |||
1190 | /* Register IRQ */ | ||
1191 | retval = request_irq(itv->dev->irq, ivtv_irq_handler, | ||
1192 | IRQF_SHARED | IRQF_DISABLED, itv->name, (void *)itv); | ||
1193 | if (retval) { | ||
1194 | IVTV_ERR("Failed to register irq %d\n", retval); | ||
1195 | goto free_streams; | ||
1196 | } | ||
1197 | |||
1198 | /* On a cx23416 this seems to be able to enable DMA to the chip? */ | ||
1199 | if (!itv->has_cx23415) | ||
1200 | write_reg_sync(0x03, IVTV_REG_DMACONTROL); | ||
1201 | |||
1202 | /* Default interrupts enabled. For the PVR350 this includes the | ||
1203 | decoder VSYNC interrupt, which is always on. It is not only used | ||
1204 | during decoding but also by the OSD. | ||
1205 | Some old PVR250 cards had a cx23415, so testing for that is too | ||
1206 | general. Instead test if the card has video output capability. */ | ||
1207 | if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) | ||
1208 | ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_INIT | IVTV_IRQ_DEC_VSYNC); | ||
1209 | else | ||
1210 | ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_INIT); | ||
1211 | |||
1212 | if (itv->has_cx23415) | ||
1213 | ivtv_set_osd_alpha(itv); | ||
1214 | |||
1215 | IVTV_INFO("Initialized %s, card #%d\n", itv->card_name, itv->num); | ||
1216 | |||
1217 | return 0; | ||
1218 | |||
1219 | free_irq: | ||
1220 | free_irq(itv->dev->irq, (void *)itv); | ||
1221 | free_streams: | ||
1222 | ivtv_streams_cleanup(itv); | ||
1223 | free_i2c: | ||
1224 | exit_ivtv_i2c(itv); | ||
1225 | free_io: | ||
1226 | ivtv_iounmap(itv); | ||
1227 | free_mem: | ||
1228 | release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE); | ||
1229 | release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE); | ||
1230 | if (itv->has_cx23415) | ||
1231 | release_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE); | ||
1232 | free_workqueue: | ||
1233 | destroy_workqueue(itv->irq_work_queues); | ||
1234 | err: | ||
1235 | if (retval == 0) | ||
1236 | retval = -ENODEV; | ||
1237 | IVTV_ERR("Error %d on initialization\n", retval); | ||
1238 | |||
1239 | kfree(ivtv_cards[ivtv_cards_active]); | ||
1240 | ivtv_cards[ivtv_cards_active] = NULL; | ||
1241 | return retval; | ||
1242 | } | ||
1243 | |||
1244 | static void ivtv_remove(struct pci_dev *pci_dev) | ||
1245 | { | ||
1246 | struct ivtv *itv = pci_get_drvdata(pci_dev); | ||
1247 | |||
1248 | IVTV_DEBUG_INFO("Removing Card #%d.\n", itv->num); | ||
1249 | |||
1250 | /* Stop all captures */ | ||
1251 | IVTV_DEBUG_INFO(" Stopping all streams.\n"); | ||
1252 | if (atomic_read(&itv->capturing) > 0) | ||
1253 | ivtv_stop_all_captures(itv); | ||
1254 | |||
1255 | /* Stop all decoding */ | ||
1256 | IVTV_DEBUG_INFO(" Stopping decoding.\n"); | ||
1257 | if (atomic_read(&itv->decoding) > 0) { | ||
1258 | int type; | ||
1259 | |||
1260 | if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) | ||
1261 | type = IVTV_DEC_STREAM_TYPE_YUV; | ||
1262 | else | ||
1263 | type = IVTV_DEC_STREAM_TYPE_MPG; | ||
1264 | ivtv_stop_v4l2_decode_stream(&itv->streams[type], | ||
1265 | VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY, 0); | ||
1266 | } | ||
1267 | |||
1268 | /* Interrupts */ | ||
1269 | IVTV_DEBUG_INFO(" Disabling interrupts.\n"); | ||
1270 | ivtv_set_irq_mask(itv, 0xffffffff); | ||
1271 | del_timer_sync(&itv->dma_timer); | ||
1272 | |||
1273 | /* Stop all Work Queues */ | ||
1274 | IVTV_DEBUG_INFO(" Stop Work Queues.\n"); | ||
1275 | flush_workqueue(itv->irq_work_queues); | ||
1276 | destroy_workqueue(itv->irq_work_queues); | ||
1277 | |||
1278 | IVTV_DEBUG_INFO(" Stopping Firmware.\n"); | ||
1279 | ivtv_halt_firmware(itv); | ||
1280 | |||
1281 | IVTV_DEBUG_INFO(" Unregistering v4l devices.\n"); | ||
1282 | ivtv_streams_cleanup(itv); | ||
1283 | IVTV_DEBUG_INFO(" Freeing dma resources.\n"); | ||
1284 | ivtv_udma_free(itv); | ||
1285 | |||
1286 | exit_ivtv_i2c(itv); | ||
1287 | |||
1288 | IVTV_DEBUG_INFO(" Releasing irq.\n"); | ||
1289 | free_irq(itv->dev->irq, (void *)itv); | ||
1290 | |||
1291 | if (itv->dev) { | ||
1292 | ivtv_iounmap(itv); | ||
1293 | } | ||
1294 | |||
1295 | IVTV_DEBUG_INFO(" Releasing mem.\n"); | ||
1296 | release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE); | ||
1297 | release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE); | ||
1298 | if (itv->has_cx23415) | ||
1299 | release_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE); | ||
1300 | |||
1301 | pci_disable_device(itv->dev); | ||
1302 | |||
1303 | IVTV_INFO("Removed %s, card #%d\n", itv->card_name, itv->num); | ||
1304 | } | ||
1305 | |||
1306 | /* define a pci_driver for card detection */ | ||
1307 | static struct pci_driver ivtv_pci_driver = { | ||
1308 | .name = "ivtv", | ||
1309 | .id_table = ivtv_pci_tbl, | ||
1310 | .probe = ivtv_probe, | ||
1311 | .remove = ivtv_remove, | ||
1312 | }; | ||
1313 | |||
1314 | static int module_start(void) | ||
1315 | { | ||
1316 | printk(KERN_INFO "ivtv: ==================== START INIT IVTV ====================\n"); | ||
1317 | printk(KERN_INFO "ivtv: version %s (" VERMAGIC_STRING ") loading\n", IVTV_VERSION); | ||
1318 | |||
1319 | memset(ivtv_cards, 0, sizeof(ivtv_cards)); | ||
1320 | |||
1321 | /* Validate parameters */ | ||
1322 | if (ivtv_first_minor < 0 || ivtv_first_minor >= IVTV_MAX_CARDS) { | ||
1323 | printk(KERN_ERR "ivtv: ivtv_first_minor must be between 0 and %d. Exiting...\n", | ||
1324 | IVTV_MAX_CARDS - 1); | ||
1325 | return -1; | ||
1326 | } | ||
1327 | |||
1328 | if (ivtv_debug < 0 || ivtv_debug > 511) { | ||
1329 | ivtv_debug = 0; | ||
1330 | printk(KERN_INFO "ivtv: debug value must be >= 0 and <= 511!\n"); | ||
1331 | } | ||
1332 | |||
1333 | if (pci_register_driver(&ivtv_pci_driver)) { | ||
1334 | printk(KERN_ERR "ivtv: Error detecting PCI card\n"); | ||
1335 | return -ENODEV; | ||
1336 | } | ||
1337 | printk(KERN_INFO "ivtv: ==================== END INIT IVTV ====================\n"); | ||
1338 | return 0; | ||
1339 | } | ||
1340 | |||
1341 | static void module_cleanup(void) | ||
1342 | { | ||
1343 | int i, j; | ||
1344 | |||
1345 | pci_unregister_driver(&ivtv_pci_driver); | ||
1346 | |||
1347 | for (i = 0; i < ivtv_cards_active; i++) { | ||
1348 | if (ivtv_cards[i] == NULL) | ||
1349 | continue; | ||
1350 | for (j = 0; j < IVTV_VBI_FRAMES; j++) { | ||
1351 | kfree(ivtv_cards[i]->vbi.sliced_mpeg_data[j]); | ||
1352 | } | ||
1353 | kfree(ivtv_cards[i]); | ||
1354 | } | ||
1355 | } | ||
1356 | |||
1357 | /* Note: These symbols are exported because they are used by the ivtv-fb | ||
1358 | framebuffer module and an infrared module for the IR-blaster. */ | ||
1359 | EXPORT_SYMBOL(ivtv_set_irq_mask); | ||
1360 | EXPORT_SYMBOL(ivtv_cards_active); | ||
1361 | EXPORT_SYMBOL(ivtv_cards); | ||
1362 | EXPORT_SYMBOL(ivtv_api); | ||
1363 | EXPORT_SYMBOL(ivtv_vapi); | ||
1364 | EXPORT_SYMBOL(ivtv_vapi_result); | ||
1365 | EXPORT_SYMBOL(ivtv_clear_irq_mask); | ||
1366 | EXPORT_SYMBOL(ivtv_debug); | ||
1367 | EXPORT_SYMBOL(ivtv_reset_ir_gpio); | ||
1368 | EXPORT_SYMBOL(ivtv_udma_setup); | ||
1369 | EXPORT_SYMBOL(ivtv_udma_unmap); | ||
1370 | EXPORT_SYMBOL(ivtv_udma_alloc); | ||
1371 | EXPORT_SYMBOL(ivtv_udma_prepare); | ||
1372 | |||
1373 | module_init(module_start); | ||
1374 | module_exit(module_cleanup); | ||
diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h new file mode 100644 index 000000000000..9a412d6c6d06 --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-driver.h | |||
@@ -0,0 +1,868 @@ | |||
1 | /* | ||
2 | ivtv driver internal defines and structures | ||
3 | Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> | ||
4 | Copyright (C) 2004 Chris Kennedy <c@groovy.org> | ||
5 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2 of the License, or | ||
10 | (at your option) any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; if not, write to the Free Software | ||
19 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | */ | ||
21 | |||
22 | #ifndef IVTV_DRIVER_H | ||
23 | #define IVTV_DRIVER_H | ||
24 | |||
25 | /* Internal header for ivtv project: | ||
26 | * Driver for the cx23415/6 chip. | ||
27 | * Author: Kevin Thayer (nufan_wfk at yahoo.com) | ||
28 | * License: GPL | ||
29 | * http://www.ivtvdriver.org | ||
30 | * | ||
31 | * ----- | ||
32 | * MPG600/MPG160 support by T.Adachi <tadachi@tadachi-net.com> | ||
33 | * and Takeru KOMORIYA<komoriya@paken.org> | ||
34 | * | ||
35 | * AVerMedia M179 GPIO info by Chris Pinkham <cpinkham@bc2va.org> | ||
36 | * using information provided by Jiun-Kuei Jung @ AVerMedia. | ||
37 | */ | ||
38 | |||
39 | #include <linux/version.h> | ||
40 | #include <linux/module.h> | ||
41 | #include <linux/moduleparam.h> | ||
42 | #include <linux/init.h> | ||
43 | #include <linux/delay.h> | ||
44 | #include <linux/sched.h> | ||
45 | #include <linux/fs.h> | ||
46 | #include <linux/pci.h> | ||
47 | #include <linux/interrupt.h> | ||
48 | #include <linux/spinlock.h> | ||
49 | #include <linux/i2c.h> | ||
50 | #include <linux/i2c-algo-bit.h> | ||
51 | #include <linux/list.h> | ||
52 | #include <linux/unistd.h> | ||
53 | #include <linux/byteorder/swab.h> | ||
54 | #include <linux/pagemap.h> | ||
55 | #include <linux/workqueue.h> | ||
56 | #include <linux/mutex.h> | ||
57 | #include <asm/uaccess.h> | ||
58 | #include <asm/system.h> | ||
59 | |||
60 | #include <linux/dvb/video.h> | ||
61 | #include <linux/dvb/audio.h> | ||
62 | #include <media/v4l2-common.h> | ||
63 | #include <media/tuner.h> | ||
64 | #include <media/cx2341x.h> | ||
65 | |||
66 | /* #define HAVE_XC3028 1 */ | ||
67 | |||
68 | #include <media/ivtv.h> | ||
69 | |||
70 | #ifdef CONFIG_LIRC_I2C | ||
71 | # error "This driver is not compatible with the LIRC I2C kernel configuration option." | ||
72 | #endif /* CONFIG_LIRC_I2C */ | ||
73 | |||
74 | #ifndef CONFIG_PCI | ||
75 | # error "This driver requires kernel PCI support." | ||
76 | #endif /* CONFIG_PCI */ | ||
77 | |||
78 | #define IVTV_ENCODER_OFFSET 0x00000000 | ||
79 | #define IVTV_ENCODER_SIZE 0x00800000 /* Last half isn't needed 0x01000000 */ | ||
80 | |||
81 | #define IVTV_DECODER_OFFSET 0x01000000 | ||
82 | #define IVTV_DECODER_SIZE 0x00800000 /* Last half isn't needed 0x01000000 */ | ||
83 | |||
84 | #define IVTV_REG_OFFSET 0x02000000 | ||
85 | #define IVTV_REG_SIZE 0x00010000 | ||
86 | |||
87 | /* Buffers on hardware offsets */ | ||
88 | #define IVTV_YUV_BUFFER_OFFSET 0x001a8600 /* First YUV Buffer */ | ||
89 | #define IVTV_YUV_BUFFER_OFFSET_1 0x00240400 /* Second YUV Buffer */ | ||
90 | #define IVTV_YUV_BUFFER_OFFSET_2 0x002d8200 /* Third YUV Buffer */ | ||
91 | #define IVTV_YUV_BUFFER_OFFSET_3 0x00370000 /* Fourth YUV Buffer */ | ||
92 | #define IVTV_YUV_BUFFER_UV_OFFSET 0x65400 /* Offset to UV Buffer */ | ||
93 | |||
94 | /* Offset to filter table in firmware */ | ||
95 | #define IVTV_YUV_HORIZONTAL_FILTER_OFFSET 0x025d8 | ||
96 | #define IVTV_YUV_VERTICAL_FILTER_OFFSET 0x03358 | ||
97 | |||
98 | extern const u32 yuv_offset[4]; | ||
99 | |||
100 | /* Maximum ivtv driver instances. | ||
101 | Based on 6 PVR500s each with two PVR15s... | ||
102 | TODO: make this dynamic. I believe it is only a global in order to support | ||
103 | ivtv-fb. There must be a better way to do that. */ | ||
104 | #define IVTV_MAX_CARDS 12 | ||
105 | |||
106 | /* Supported cards */ | ||
107 | #define IVTV_CARD_PVR_250 0 /* WinTV PVR 250 */ | ||
108 | #define IVTV_CARD_PVR_350 1 /* encoder, decoder, tv-out */ | ||
109 | #define IVTV_CARD_PVR_150 2 /* WinTV PVR 150 and PVR 500 (really just two | ||
110 | PVR150s on one PCI board) */ | ||
111 | #define IVTV_CARD_M179 3 /* AVerMedia M179 (encoder only) */ | ||
112 | #define IVTV_CARD_MPG600 4 /* Kuroutoshikou ITVC16-STVLP/YUAN MPG600, encoder only */ | ||
113 | #define IVTV_CARD_MPG160 5 /* Kuroutoshikou ITVC15-STVLP/YUAN MPG160 | ||
114 | cx23415 based, but does not have tv-out */ | ||
115 | #define IVTV_CARD_PG600 6 /* YUAN PG600/DIAMONDMM PVR-550 based on the CX Falcon 2 */ | ||
116 | #define IVTV_CARD_AVC2410 7 /* Adaptec AVC-2410 */ | ||
117 | #define IVTV_CARD_AVC2010 8 /* Adaptec AVD-2010 (No Tuner) */ | ||
118 | #define IVTV_CARD_TG5000TV 9 /* NAGASE TRANSGEAR 5000TV, encoder only */ | ||
119 | #define IVTV_CARD_VA2000MAX_SNT6 10 /* VA2000MAX-STN6 */ | ||
120 | #define IVTV_CARD_CX23416GYC 11 /* Kuroutoshikou CX23416GYC-STVLP (Yuan MPG600GR OEM) */ | ||
121 | #define IVTV_CARD_GV_MVPRX 12 /* I/O Data GV-MVP/RX, RX2, RX2W */ | ||
122 | #define IVTV_CARD_GV_MVPRX2E 13 /* I/O Data GV-MVP/RX2E */ | ||
123 | #define IVTV_CARD_GOTVIEW_PCI_DVD 14 /* GotView PCI DVD */ | ||
124 | #define IVTV_CARD_GOTVIEW_PCI_DVD2 15 /* GotView PCI DVD2 */ | ||
125 | #define IVTV_CARD_YUAN_MPC622 16 /* Yuan MPC622 miniPCI */ | ||
126 | #define IVTV_CARD_DCTMTVP1 17 /* DIGITAL COWBOY DCT-MTVP1 */ | ||
127 | #ifdef HAVE_XC3028 | ||
128 | #define IVTV_CARD_PG600V2 18 /* Yuan PG600V2/GotView PCI DVD Lite/Club3D ZAP-TV1x01 */ | ||
129 | #define IVTV_CARD_LAST 18 | ||
130 | #else | ||
131 | #define IVTV_CARD_LAST 17 | ||
132 | #endif | ||
133 | |||
134 | /* Variants of existing cards but with the same PCI IDs. The driver | ||
135 | detects these based on other device information. | ||
136 | These cards must always come last. | ||
137 | New cards must be inserted above, and the indices of the cards below | ||
138 | must be adjusted accordingly. */ | ||
139 | |||
140 | /* PVR-350 V1 (uses saa7114) */ | ||
141 | #define IVTV_CARD_PVR_350_V1 (IVTV_CARD_LAST+1) | ||
142 | /* 2 variants of Kuroutoshikou CX23416GYC-STVLP (Yuan MPG600GR OEM) */ | ||
143 | #define IVTV_CARD_CX23416GYC_NOGR (IVTV_CARD_LAST+2) | ||
144 | #define IVTV_CARD_CX23416GYC_NOGRYCS (IVTV_CARD_LAST+3) | ||
145 | |||
146 | #define IVTV_ENC_STREAM_TYPE_MPG 0 | ||
147 | #define IVTV_ENC_STREAM_TYPE_YUV 1 | ||
148 | #define IVTV_ENC_STREAM_TYPE_VBI 2 | ||
149 | #define IVTV_ENC_STREAM_TYPE_PCM 3 | ||
150 | #define IVTV_ENC_STREAM_TYPE_RAD 4 | ||
151 | #define IVTV_DEC_STREAM_TYPE_MPG 5 | ||
152 | #define IVTV_DEC_STREAM_TYPE_VBI 6 | ||
153 | #define IVTV_DEC_STREAM_TYPE_VOUT 7 | ||
154 | #define IVTV_DEC_STREAM_TYPE_YUV 8 | ||
155 | #define IVTV_MAX_STREAMS 9 | ||
156 | |||
157 | #define IVTV_V4L2_DEC_MPG_OFFSET 16 /* offset from 0 to register decoder mpg v4l2 minors on */ | ||
158 | #define IVTV_V4L2_ENC_PCM_OFFSET 24 /* offset from 0 to register pcm v4l2 minors on */ | ||
159 | #define IVTV_V4L2_ENC_YUV_OFFSET 32 /* offset from 0 to register yuv v4l2 minors on */ | ||
160 | #define IVTV_V4L2_DEC_YUV_OFFSET 48 /* offset from 0 to register decoder yuv v4l2 minors on */ | ||
161 | #define IVTV_V4L2_DEC_VBI_OFFSET 8 /* offset from 0 to register decoder vbi input v4l2 minors on */ | ||
162 | #define IVTV_V4L2_DEC_VOUT_OFFSET 16 /* offset from 0 to register vbi output v4l2 minors on */ | ||
163 | |||
164 | #define IVTV_ENC_MEM_START 0x00000000 | ||
165 | #define IVTV_DEC_MEM_START 0x01000000 | ||
166 | |||
167 | /* system vendor and device IDs */ | ||
168 | #define PCI_VENDOR_ID_ICOMP 0x4444 | ||
169 | #define PCI_DEVICE_ID_IVTV15 0x0803 | ||
170 | #define PCI_DEVICE_ID_IVTV16 0x0016 | ||
171 | |||
172 | /* subsystem vendor ID */ | ||
173 | #define IVTV_PCI_ID_HAUPPAUGE 0x0070 | ||
174 | #define IVTV_PCI_ID_HAUPPAUGE_ALT1 0x0270 | ||
175 | #define IVTV_PCI_ID_HAUPPAUGE_ALT2 0x4070 | ||
176 | #define IVTV_PCI_ID_ADAPTEC 0x9005 | ||
177 | #define IVTV_PCI_ID_AVERMEDIA 0x1461 | ||
178 | #define IVTV_PCI_ID_YUAN1 0x12ab | ||
179 | #define IVTV_PCI_ID_YUAN2 0xff01 | ||
180 | #define IVTV_PCI_ID_YUAN3 0xffab | ||
181 | #define IVTV_PCI_ID_YUAN4 0xfbab | ||
182 | #define IVTV_PCI_ID_DIAMONDMM 0xff92 | ||
183 | #define IVTV_PCI_ID_IODATA 0x10fc | ||
184 | #define IVTV_PCI_ID_MELCO 0x1154 | ||
185 | #define IVTV_PCI_ID_GOTVIEW1 0xffac | ||
186 | #define IVTV_PCI_ID_GOTVIEW2 0xffad | ||
187 | |||
188 | /* Decoder Buffer hardware size on Chip */ | ||
189 | #define IVTV_DEC_MAX_BUF 0x00100000 /* max bytes in decoder buffer */ | ||
190 | #define IVTV_DEC_MIN_BUF 0x00010000 /* min bytes in dec buffer */ | ||
191 | |||
192 | /* ======================================================================== */ | ||
193 | /* ========================== START USER SETTABLE DMA VARIABLES =========== */ | ||
194 | /* ======================================================================== */ | ||
195 | |||
196 | #define IVTV_DMA_SG_OSD_ENT (2883584/PAGE_SIZE) /* sg entities */ | ||
197 | |||
198 | /* DMA Buffers, Default size in MB allocated */ | ||
199 | #define IVTV_DEFAULT_ENC_MPG_BUFFERS 4 | ||
200 | #define IVTV_DEFAULT_ENC_YUV_BUFFERS 2 | ||
201 | #define IVTV_DEFAULT_ENC_VBI_BUFFERS 1 | ||
202 | #define IVTV_DEFAULT_ENC_PCM_BUFFERS 1 | ||
203 | #define IVTV_DEFAULT_DEC_MPG_BUFFERS 1 | ||
204 | #define IVTV_DEFAULT_DEC_YUV_BUFFERS 1 | ||
205 | #define IVTV_DEFAULT_DEC_VBI_BUFFERS 1 | ||
206 | |||
207 | /* ======================================================================== */ | ||
208 | /* ========================== END USER SETTABLE DMA VARIABLES ============= */ | ||
209 | /* ======================================================================== */ | ||
210 | |||
211 | /* Decoder Status Register */ | ||
212 | #define IVTV_DMA_ERR_LIST 0x00000010 | ||
213 | #define IVTV_DMA_ERR_WRITE 0x00000008 | ||
214 | #define IVTV_DMA_ERR_READ 0x00000004 | ||
215 | #define IVTV_DMA_SUCCESS_WRITE 0x00000002 | ||
216 | #define IVTV_DMA_SUCCESS_READ 0x00000001 | ||
217 | #define IVTV_DMA_READ_ERR (IVTV_DMA_ERR_LIST | IVTV_DMA_ERR_READ) | ||
218 | #define IVTV_DMA_WRITE_ERR (IVTV_DMA_ERR_LIST | IVTV_DMA_ERR_WRITE) | ||
219 | #define IVTV_DMA_ERR (IVTV_DMA_ERR_LIST | IVTV_DMA_ERR_WRITE | IVTV_DMA_ERR_READ) | ||
220 | |||
221 | /* DMA Registers */ | ||
222 | #define IVTV_REG_DMAXFER (0x0000) | ||
223 | #define IVTV_REG_DMASTATUS (0x0004) | ||
224 | #define IVTV_REG_DECDMAADDR (0x0008) | ||
225 | #define IVTV_REG_ENCDMAADDR (0x000c) | ||
226 | #define IVTV_REG_DMACONTROL (0x0010) | ||
227 | #define IVTV_REG_IRQSTATUS (0x0040) | ||
228 | #define IVTV_REG_IRQMASK (0x0048) | ||
229 | |||
230 | /* Setup Registers */ | ||
231 | #define IVTV_REG_ENC_SDRAM_REFRESH (0x07F8) | ||
232 | #define IVTV_REG_ENC_SDRAM_PRECHARGE (0x07FC) | ||
233 | #define IVTV_REG_DEC_SDRAM_REFRESH (0x08F8) | ||
234 | #define IVTV_REG_DEC_SDRAM_PRECHARGE (0x08FC) | ||
235 | #define IVTV_REG_VDM (0x2800) | ||
236 | #define IVTV_REG_AO (0x2D00) | ||
237 | #define IVTV_REG_BYTEFLUSH (0x2D24) | ||
238 | #define IVTV_REG_SPU (0x9050) | ||
239 | #define IVTV_REG_HW_BLOCKS (0x9054) | ||
240 | #define IVTV_REG_VPU (0x9058) | ||
241 | #define IVTV_REG_APU (0xA064) | ||
242 | |||
243 | #define IVTV_IRQ_ENC_START_CAP (0x1 << 31) | ||
244 | #define IVTV_IRQ_ENC_EOS (0x1 << 30) | ||
245 | #define IVTV_IRQ_ENC_VBI_CAP (0x1 << 29) | ||
246 | #define IVTV_IRQ_ENC_VIM_RST (0x1 << 28) | ||
247 | #define IVTV_IRQ_ENC_DMA_COMPLETE (0x1 << 27) | ||
248 | #define IVTV_IRQ_DEC_AUD_MODE_CHG (0x1 << 24) | ||
249 | #define IVTV_IRQ_DEC_DATA_REQ (0x1 << 22) | ||
250 | #define IVTV_IRQ_DEC_DMA_COMPLETE (0x1 << 20) | ||
251 | #define IVTV_IRQ_DEC_VBI_RE_INSERT (0x1 << 19) | ||
252 | #define IVTV_IRQ_DMA_ERR (0x1 << 18) | ||
253 | #define IVTV_IRQ_DMA_WRITE (0x1 << 17) | ||
254 | #define IVTV_IRQ_DMA_READ (0x1 << 16) | ||
255 | #define IVTV_IRQ_DEC_VSYNC (0x1 << 10) | ||
256 | |||
257 | /* IRQ Masks */ | ||
258 | #define IVTV_IRQ_MASK_INIT (IVTV_IRQ_DMA_ERR|IVTV_IRQ_ENC_DMA_COMPLETE|IVTV_IRQ_DMA_READ) | ||
259 | |||
260 | #define IVTV_IRQ_MASK_CAPTURE (IVTV_IRQ_ENC_START_CAP | IVTV_IRQ_ENC_EOS) | ||
261 | #define IVTV_IRQ_MASK_DECODE (IVTV_IRQ_DEC_DATA_REQ|IVTV_IRQ_DEC_AUD_MODE_CHG) | ||
262 | |||
263 | /* i2c stuff */ | ||
264 | #define I2C_CLIENTS_MAX 16 | ||
265 | |||
266 | /* debugging */ | ||
267 | |||
268 | #define IVTV_DBGFLG_WARN (1 << 0) | ||
269 | #define IVTV_DBGFLG_INFO (1 << 1) | ||
270 | #define IVTV_DBGFLG_API (1 << 2) | ||
271 | #define IVTV_DBGFLG_DMA (1 << 3) | ||
272 | #define IVTV_DBGFLG_IOCTL (1 << 4) | ||
273 | #define IVTV_DBGFLG_I2C (1 << 5) | ||
274 | #define IVTV_DBGFLG_IRQ (1 << 6) | ||
275 | #define IVTV_DBGFLG_DEC (1 << 7) | ||
276 | #define IVTV_DBGFLG_YUV (1 << 8) | ||
277 | |||
278 | /* NOTE: extra space before comma in 'itv->num , ## args' is required for | ||
279 | gcc-2.95, otherwise it won't compile. */ | ||
280 | #define IVTV_DEBUG(x, type, fmt, args...) \ | ||
281 | do { \ | ||
282 | if ((x) & ivtv_debug) \ | ||
283 | printk(KERN_INFO "ivtv%d " type ": " fmt, itv->num , ## args); \ | ||
284 | } while (0) | ||
285 | #define IVTV_DEBUG_WARN(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_WARN, "warning", fmt , ## args) | ||
286 | #define IVTV_DEBUG_INFO(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_INFO, "info",fmt , ## args) | ||
287 | #define IVTV_DEBUG_API(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_API, "api", fmt , ## args) | ||
288 | #define IVTV_DEBUG_DMA(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_DMA, "dma", fmt , ## args) | ||
289 | #define IVTV_DEBUG_IOCTL(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_IOCTL, "ioctl", fmt , ## args) | ||
290 | #define IVTV_DEBUG_I2C(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_I2C, "i2c", fmt , ## args) | ||
291 | #define IVTV_DEBUG_IRQ(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_IRQ, "irq", fmt , ## args) | ||
292 | #define IVTV_DEBUG_DEC(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_DEC, "dec", fmt , ## args) | ||
293 | #define IVTV_DEBUG_YUV(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_YUV, "yuv", fmt , ## args) | ||
294 | |||
295 | #define IVTV_FB_DEBUG(x, type, fmt, args...) \ | ||
296 | do { \ | ||
297 | if ((x) & ivtv_debug) \ | ||
298 | printk(KERN_INFO "ivtv%d-fb " type ": " fmt, itv->num , ## args); \ | ||
299 | } while (0) | ||
300 | #define IVTV_FB_DEBUG_WARN(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_WARN, "warning", fmt , ## args) | ||
301 | #define IVTV_FB_DEBUG_INFO(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_INFO, "info", fmt , ## args) | ||
302 | #define IVTV_FB_DEBUG_API(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_API, "api", fmt , ## args) | ||
303 | #define IVTV_FB_DEBUG_DMA(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_DMA, "dma", fmt , ## args) | ||
304 | #define IVTV_FB_DEBUG_IOCTL(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_IOCTL, "ioctl", fmt , ## args) | ||
305 | #define IVTV_FB_DEBUG_I2C(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_I2C, "i2c", fmt , ## args) | ||
306 | #define IVTV_FB_DEBUG_IRQ(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_IRQ, "irq", fmt , ## args) | ||
307 | #define IVTV_FB_DEBUG_DEC(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_DEC, "dec", fmt , ## args) | ||
308 | #define IVTV_FB_DEBUG_YUV(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_YUV, "yuv", fmt , ## args) | ||
309 | |||
310 | /* Standard kernel messages */ | ||
311 | #define IVTV_ERR(fmt, args...) printk(KERN_ERR "ivtv%d: " fmt, itv->num , ## args) | ||
312 | #define IVTV_WARN(fmt, args...) printk(KERN_WARNING "ivtv%d: " fmt, itv->num , ## args) | ||
313 | #define IVTV_INFO(fmt, args...) printk(KERN_INFO "ivtv%d: " fmt, itv->num , ## args) | ||
314 | #define IVTV_FB_ERR(fmt, args...) printk(KERN_ERR "ivtv%d-fb: " fmt, itv->num , ## args) | ||
315 | #define IVTV_FB_WARN(fmt, args...) printk(KERN_WARNING "ivtv%d-fb: " fmt, itv->num , ## args) | ||
316 | #define IVTV_FB_INFO(fmt, args...) printk(KERN_INFO "ivtv%d-fb: " fmt, itv->num , ## args) | ||
317 | |||
318 | /* Values for IVTV_API_DEC_PLAYBACK_SPEED mpeg_frame_type_mask parameter: */ | ||
319 | #define MPEG_FRAME_TYPE_IFRAME 1 | ||
320 | #define MPEG_FRAME_TYPE_IFRAME_PFRAME 3 | ||
321 | #define MPEG_FRAME_TYPE_ALL 7 | ||
322 | |||
323 | /* output modes (cx23415 only) */ | ||
324 | #define OUT_NONE 0 | ||
325 | #define OUT_MPG 1 | ||
326 | #define OUT_YUV 2 | ||
327 | #define OUT_UDMA_YUV 3 | ||
328 | #define OUT_PASSTHROUGH 4 | ||
329 | |||
330 | #define IVTV_MAX_PGM_INDEX (400) | ||
331 | |||
332 | extern int ivtv_debug; | ||
333 | |||
334 | |||
335 | struct ivtv_options { | ||
336 | int megabytes[IVTV_MAX_STREAMS]; /* Size in megabytes of each stream */ | ||
337 | int cardtype; /* force card type on load */ | ||
338 | int tuner; /* set tuner on load */ | ||
339 | int radio; /* enable/disable radio */ | ||
340 | int newi2c; /* New I2C algorithm */ | ||
341 | }; | ||
342 | |||
343 | #define IVTV_MBOX_DMA_START 6 | ||
344 | #define IVTV_MBOX_DMA_END 8 | ||
345 | #define IVTV_MBOX_DMA 9 | ||
346 | #define IVTV_MBOX_FIELD_DISPLAYED 8 | ||
347 | |||
348 | /* ivtv-specific mailbox template */ | ||
349 | struct ivtv_mailbox { | ||
350 | u32 flags; | ||
351 | u32 cmd; | ||
352 | u32 retval; | ||
353 | u32 timeout; | ||
354 | u32 data[CX2341X_MBOX_MAX_DATA]; | ||
355 | }; | ||
356 | |||
357 | struct ivtv_api_cache { | ||
358 | unsigned long last_jiffies; /* when last command was issued */ | ||
359 | u32 data[CX2341X_MBOX_MAX_DATA]; /* last sent api data */ | ||
360 | }; | ||
361 | |||
362 | struct ivtv_mailbox_data { | ||
363 | volatile struct ivtv_mailbox __iomem *mbox; | ||
364 | /* Bits 0-2 are for the encoder mailboxes, 0-1 are for the decoder mailboxes. | ||
365 | If the bit is set, then the corresponding mailbox is in use by the driver. */ | ||
366 | unsigned long busy; | ||
367 | u8 max_mbox; | ||
368 | }; | ||
369 | |||
370 | /* per-buffer bit flags */ | ||
371 | #define IVTV_F_B_NEED_BUF_SWAP 0 /* this buffer should be byte swapped */ | ||
372 | |||
373 | /* per-stream, s_flags */ | ||
374 | #define IVTV_F_S_DMA_PENDING 0 /* this stream has pending DMA */ | ||
375 | #define IVTV_F_S_DMA_HAS_VBI 1 /* the current DMA request also requests VBI data */ | ||
376 | #define IVTV_F_S_NEEDS_DATA 2 /* this decoding stream needs more data */ | ||
377 | |||
378 | #define IVTV_F_S_CLAIMED 3 /* this stream is claimed */ | ||
379 | #define IVTV_F_S_STREAMING 4 /* the fw is decoding/encoding this stream */ | ||
380 | #define IVTV_F_S_INTERNAL_USE 5 /* this stream is used internally (sliced VBI processing) */ | ||
381 | #define IVTV_F_S_PASSTHROUGH 6 /* this stream is in passthrough mode */ | ||
382 | #define IVTV_F_S_STREAMOFF 7 /* signal end of stream EOS */ | ||
383 | #define IVTV_F_S_APPL_IO 8 /* this stream is used read/written by an application */ | ||
384 | |||
385 | /* per-ivtv, i_flags */ | ||
386 | #define IVTV_F_I_DMA 0 /* DMA in progress */ | ||
387 | #define IVTV_F_I_UDMA 1 /* UDMA in progress */ | ||
388 | #define IVTV_F_I_UDMA_PENDING 2 /* UDMA pending */ | ||
389 | #define IVTV_F_I_SPEED_CHANGE 3 /* A speed change is in progress */ | ||
390 | #define IVTV_F_I_EOS 4 /* End of encoder stream reached */ | ||
391 | #define IVTV_F_I_RADIO_USER 5 /* The radio tuner is selected */ | ||
392 | #define IVTV_F_I_DIG_RST 6 /* Reset digitizer */ | ||
393 | #define IVTV_F_I_DEC_YUV 7 /* YUV instead of MPG is being decoded */ | ||
394 | #define IVTV_F_I_ENC_VBI 8 /* VBI DMA */ | ||
395 | #define IVTV_F_I_UPDATE_CC 9 /* CC should be updated */ | ||
396 | #define IVTV_F_I_UPDATE_WSS 10 /* WSS should be updated */ | ||
397 | #define IVTV_F_I_UPDATE_VPS 11 /* VPS should be updated */ | ||
398 | #define IVTV_F_I_DECODING_YUV 12 /* this stream is YUV frame decoding */ | ||
399 | #define IVTV_F_I_ENC_PAUSED 13 /* the encoder is paused */ | ||
400 | #define IVTV_F_I_VALID_DEC_TIMINGS 14 /* last_dec_timing is valid */ | ||
401 | #define IVTV_F_I_WORK_HANDLER_VBI 15 /* there is work to be done for VBI */ | ||
402 | #define IVTV_F_I_WORK_HANDLER_YUV 16 /* there is work to be done for YUV */ | ||
403 | |||
404 | /* Event notifications */ | ||
405 | #define IVTV_F_I_EV_DEC_STOPPED 28 /* decoder stopped event */ | ||
406 | #define IVTV_F_I_EV_VSYNC 29 /* VSYNC event */ | ||
407 | #define IVTV_F_I_EV_VSYNC_FIELD 30 /* VSYNC event field (0 = first, 1 = second field) */ | ||
408 | #define IVTV_F_I_EV_VSYNC_ENABLED 31 /* VSYNC event enabled */ | ||
409 | |||
410 | /* Scatter-Gather array element, used in DMA transfers */ | ||
411 | struct ivtv_SG_element { | ||
412 | u32 src; | ||
413 | u32 dst; | ||
414 | u32 size; | ||
415 | }; | ||
416 | |||
417 | struct ivtv_user_dma { | ||
418 | struct mutex lock; | ||
419 | int page_count; | ||
420 | struct page *map[IVTV_DMA_SG_OSD_ENT]; | ||
421 | |||
422 | /* Base Dev SG Array for cx23415/6 */ | ||
423 | struct ivtv_SG_element SGarray[IVTV_DMA_SG_OSD_ENT]; | ||
424 | dma_addr_t SG_handle; | ||
425 | int SG_length; | ||
426 | |||
427 | /* SG List of Buffers */ | ||
428 | struct scatterlist SGlist[IVTV_DMA_SG_OSD_ENT]; | ||
429 | }; | ||
430 | |||
431 | struct ivtv_dma_page_info { | ||
432 | unsigned long uaddr; | ||
433 | unsigned long first; | ||
434 | unsigned long last; | ||
435 | unsigned int offset; | ||
436 | unsigned int tail; | ||
437 | int page_count; | ||
438 | }; | ||
439 | |||
440 | struct ivtv_buffer { | ||
441 | struct list_head list; | ||
442 | dma_addr_t dma_handle; | ||
443 | unsigned long b_flags; | ||
444 | char *buf; | ||
445 | |||
446 | u32 bytesused; | ||
447 | u32 readpos; | ||
448 | }; | ||
449 | |||
450 | struct ivtv_queue { | ||
451 | struct list_head list; | ||
452 | u32 buffers; | ||
453 | u32 length; | ||
454 | u32 bytesused; | ||
455 | }; | ||
456 | |||
457 | struct ivtv; /* forward reference */ | ||
458 | |||
459 | struct ivtv_stream { | ||
460 | /* These first four fields are always set, even if the stream | ||
461 | is not actually created. */ | ||
462 | struct video_device *v4l2dev; /* NULL when stream not created */ | ||
463 | struct ivtv *itv; /* for ease of use */ | ||
464 | const char *name; /* name of the stream */ | ||
465 | int type; /* stream type */ | ||
466 | |||
467 | u32 id; | ||
468 | spinlock_t qlock; /* locks access to the queues */ | ||
469 | unsigned long s_flags; /* status flags, see above */ | ||
470 | int dma; /* can be PCI_DMA_TODEVICE, | ||
471 | PCI_DMA_FROMDEVICE or | ||
472 | PCI_DMA_NONE */ | ||
473 | u32 dma_offset; | ||
474 | u32 dma_backup; | ||
475 | u64 dma_pts; | ||
476 | |||
477 | int subtype; | ||
478 | wait_queue_head_t waitq; | ||
479 | u32 dma_last_offset; | ||
480 | |||
481 | /* Buffer Stats */ | ||
482 | u32 buffers; | ||
483 | u32 buf_size; | ||
484 | u32 buffers_stolen; | ||
485 | |||
486 | /* Buffer Queues */ | ||
487 | struct ivtv_queue q_free; /* free buffers */ | ||
488 | struct ivtv_queue q_full; /* full buffers */ | ||
489 | struct ivtv_queue q_io; /* waiting for I/O */ | ||
490 | struct ivtv_queue q_dma; /* waiting for DMA */ | ||
491 | struct ivtv_queue q_predma; /* waiting for DMA */ | ||
492 | |||
493 | /* Base Dev SG Array for cx23415/6 */ | ||
494 | struct ivtv_SG_element *SGarray; | ||
495 | dma_addr_t SG_handle; | ||
496 | int SG_length; | ||
497 | |||
498 | /* SG List of Buffers */ | ||
499 | struct scatterlist *SGlist; | ||
500 | }; | ||
501 | |||
502 | struct ivtv_open_id { | ||
503 | u32 open_id; | ||
504 | int type; | ||
505 | enum v4l2_priority prio; | ||
506 | struct ivtv *itv; | ||
507 | }; | ||
508 | |||
509 | #define IVTV_YUV_UPDATE_HORIZONTAL 0x01 | ||
510 | #define IVTV_YUV_UPDATE_VERTICAL 0x02 | ||
511 | |||
512 | struct yuv_frame_info | ||
513 | { | ||
514 | u32 update; | ||
515 | int src_x; | ||
516 | int src_y; | ||
517 | unsigned int src_w; | ||
518 | unsigned int src_h; | ||
519 | int dst_x; | ||
520 | int dst_y; | ||
521 | unsigned int dst_w; | ||
522 | unsigned int dst_h; | ||
523 | int pan_x; | ||
524 | int pan_y; | ||
525 | u32 vis_w; | ||
526 | u32 vis_h; | ||
527 | u32 interlaced_y; | ||
528 | u32 interlaced_uv; | ||
529 | int tru_x; | ||
530 | u32 tru_w; | ||
531 | u32 tru_h; | ||
532 | u32 offset_y; | ||
533 | }; | ||
534 | |||
535 | #define IVTV_YUV_MODE_INTERLACED 0x00 | ||
536 | #define IVTV_YUV_MODE_PROGRESSIVE 0x01 | ||
537 | #define IVTV_YUV_MODE_AUTO 0x02 | ||
538 | #define IVTV_YUV_MODE_MASK 0x03 | ||
539 | |||
540 | #define IVTV_YUV_SYNC_EVEN 0x00 | ||
541 | #define IVTV_YUV_SYNC_ODD 0x04 | ||
542 | #define IVTV_YUV_SYNC_MASK 0x04 | ||
543 | |||
544 | struct yuv_playback_info | ||
545 | { | ||
546 | u32 reg_2834; | ||
547 | u32 reg_2838; | ||
548 | u32 reg_283c; | ||
549 | u32 reg_2840; | ||
550 | u32 reg_2844; | ||
551 | u32 reg_2848; | ||
552 | u32 reg_2854; | ||
553 | u32 reg_285c; | ||
554 | u32 reg_2864; | ||
555 | |||
556 | u32 reg_2870; | ||
557 | u32 reg_2874; | ||
558 | u32 reg_2890; | ||
559 | u32 reg_2898; | ||
560 | u32 reg_289c; | ||
561 | |||
562 | u32 reg_2918; | ||
563 | u32 reg_291c; | ||
564 | u32 reg_2920; | ||
565 | u32 reg_2924; | ||
566 | u32 reg_2928; | ||
567 | u32 reg_292c; | ||
568 | u32 reg_2930; | ||
569 | |||
570 | u32 reg_2934; | ||
571 | |||
572 | u32 reg_2938; | ||
573 | u32 reg_293c; | ||
574 | u32 reg_2940; | ||
575 | u32 reg_2944; | ||
576 | u32 reg_2948; | ||
577 | u32 reg_294c; | ||
578 | u32 reg_2950; | ||
579 | u32 reg_2954; | ||
580 | u32 reg_2958; | ||
581 | u32 reg_295c; | ||
582 | u32 reg_2960; | ||
583 | u32 reg_2964; | ||
584 | u32 reg_2968; | ||
585 | u32 reg_296c; | ||
586 | |||
587 | u32 reg_2970; | ||
588 | |||
589 | int v_filter_1; | ||
590 | int v_filter_2; | ||
591 | int h_filter; | ||
592 | |||
593 | u32 osd_x_offset; | ||
594 | u32 osd_y_offset; | ||
595 | |||
596 | u32 osd_x_pan; | ||
597 | u32 osd_y_pan; | ||
598 | |||
599 | u32 osd_vis_w; | ||
600 | u32 osd_vis_h; | ||
601 | |||
602 | int decode_height; | ||
603 | |||
604 | int frame_interlaced; | ||
605 | int frame_interlaced_last; | ||
606 | |||
607 | int lace_mode; | ||
608 | int lace_threshold; | ||
609 | int lace_sync_field; | ||
610 | |||
611 | atomic_t next_dma_frame; | ||
612 | atomic_t next_fill_frame; | ||
613 | |||
614 | u32 yuv_forced_update; | ||
615 | int update_frame; | ||
616 | struct yuv_frame_info new_frame_info[4]; | ||
617 | struct yuv_frame_info old_frame_info; | ||
618 | struct yuv_frame_info old_frame_info_args; | ||
619 | |||
620 | void *blanking_ptr; | ||
621 | dma_addr_t blanking_dmaptr; | ||
622 | }; | ||
623 | |||
624 | #define IVTV_VBI_FRAMES 32 | ||
625 | |||
626 | /* VBI data */ | ||
627 | struct vbi_info { | ||
628 | u32 dec_start; | ||
629 | u32 enc_start, enc_size; | ||
630 | int fpi; | ||
631 | u32 frame; | ||
632 | u32 dma_offset; | ||
633 | u8 cc_data_odd[256]; | ||
634 | u8 cc_data_even[256]; | ||
635 | int cc_pos; | ||
636 | u8 cc_no_update; | ||
637 | u8 vps[5]; | ||
638 | u8 vps_found; | ||
639 | int wss; | ||
640 | u8 wss_found; | ||
641 | u8 wss_no_update; | ||
642 | u32 raw_decoder_line_size; | ||
643 | u8 raw_decoder_sav_odd_field; | ||
644 | u8 raw_decoder_sav_even_field; | ||
645 | u32 sliced_decoder_line_size; | ||
646 | u8 sliced_decoder_sav_odd_field; | ||
647 | u8 sliced_decoder_sav_even_field; | ||
648 | struct v4l2_format in; | ||
649 | /* convenience pointer to sliced struct in vbi_in union */ | ||
650 | struct v4l2_sliced_vbi_format *sliced_in; | ||
651 | u32 service_set_in; | ||
652 | u32 service_set_out; | ||
653 | int insert_mpeg; | ||
654 | |||
655 | /* Buffer for the maximum of 2 * 18 * packet_size sliced VBI lines. | ||
656 | One for /dev/vbi0 and one for /dev/vbi8 */ | ||
657 | struct v4l2_sliced_vbi_data sliced_data[36]; | ||
658 | struct v4l2_sliced_vbi_data sliced_dec_data[36]; | ||
659 | |||
660 | /* Buffer for VBI data inserted into MPEG stream. | ||
661 | The first byte is a dummy byte that's never used. | ||
662 | The next 16 bytes contain the MPEG header for the VBI data, | ||
663 | the remainder is the actual VBI data. | ||
664 | The max size accepted by the MPEG VBI reinsertion turns out | ||
665 | to be 1552 bytes, which happens to be 4 + (1 + 42) * (2 * 18) bytes, | ||
666 | where 4 is a four byte header, 42 is the max sliced VBI payload, 1 is | ||
667 | a single line header byte and 2 * 18 is the number of VBI lines per frame. | ||
668 | |||
669 | However, it seems that the data must be 1K aligned, so we have to | ||
670 | pad the data until the 1 or 2 K boundary. | ||
671 | |||
672 | This pointer array will allocate 2049 bytes to store each VBI frame. */ | ||
673 | u8 *sliced_mpeg_data[IVTV_VBI_FRAMES]; | ||
674 | u32 sliced_mpeg_size[IVTV_VBI_FRAMES]; | ||
675 | struct ivtv_buffer sliced_mpeg_buf; | ||
676 | u32 inserted_frame; | ||
677 | |||
678 | u32 start[2], count; | ||
679 | u32 raw_size; | ||
680 | u32 sliced_size; | ||
681 | }; | ||
682 | |||
683 | /* forward declaration of struct defined in ivtv-cards.h */ | ||
684 | struct ivtv_card; | ||
685 | |||
686 | /* Struct to hold info about ivtv cards */ | ||
687 | struct ivtv { | ||
688 | int num; /* board number, -1 during init! */ | ||
689 | char name[8]; /* board name for printk and interrupts (e.g. 'ivtv0') */ | ||
690 | struct pci_dev *dev; /* PCI device */ | ||
691 | const struct ivtv_card *card; /* card information */ | ||
692 | const char *card_name; /* full name of the card */ | ||
693 | u8 has_cx23415; /* 1 if it is a cx23415 based card, 0 for cx23416 */ | ||
694 | u8 is_50hz; | ||
695 | u8 is_60hz; | ||
696 | u8 is_out_50hz; | ||
697 | u8 is_out_60hz; | ||
698 | u8 pvr150_workaround; /* 1 if the cx25840 needs to workaround a PVR150 bug */ | ||
699 | u8 nof_inputs; /* number of video inputs */ | ||
700 | u8 nof_audio_inputs; /* number of audio inputs */ | ||
701 | u32 v4l2_cap; /* V4L2 capabilities of card */ | ||
702 | u32 hw_flags; /* Hardware description of the board */ | ||
703 | |||
704 | /* controlling Video decoder function */ | ||
705 | int (*video_dec_func)(struct ivtv *, unsigned int, void *); | ||
706 | |||
707 | struct ivtv_options options; /* User options */ | ||
708 | int stream_buf_size[IVTV_MAX_STREAMS]; /* Stream buffer size */ | ||
709 | struct ivtv_stream streams[IVTV_MAX_STREAMS]; /* Stream data */ | ||
710 | int speed; | ||
711 | u8 speed_mute_audio; | ||
712 | unsigned long i_flags; /* global ivtv flags */ | ||
713 | atomic_t capturing; /* count number of active capture streams */ | ||
714 | atomic_t decoding; /* count number of active decoding streams */ | ||
715 | u32 irq_rr_idx; /* Round-robin stream index */ | ||
716 | int cur_dma_stream; /* index of stream doing DMA */ | ||
717 | u32 dma_data_req_offset; | ||
718 | u32 dma_data_req_size; | ||
719 | int output_mode; /* NONE, MPG, YUV, UDMA YUV, passthrough */ | ||
720 | spinlock_t lock; /* lock access to this struct */ | ||
721 | int search_pack_header; | ||
722 | |||
723 | spinlock_t dma_reg_lock; /* lock access to DMA engine registers */ | ||
724 | |||
725 | /* User based DMA for OSD */ | ||
726 | struct ivtv_user_dma udma; | ||
727 | |||
728 | int open_id; /* incremented each time an open occurs, used as unique ID. | ||
729 | starts at 1, so 0 can be used as uninitialized value | ||
730 | in the stream->id. */ | ||
731 | |||
732 | u32 base_addr; | ||
733 | u32 irqmask; | ||
734 | |||
735 | struct v4l2_prio_state prio; | ||
736 | struct workqueue_struct *irq_work_queues; | ||
737 | struct work_struct irq_work_queue; | ||
738 | struct timer_list dma_timer; /* Timer used to catch unfinished DMAs */ | ||
739 | |||
740 | struct vbi_info vbi; | ||
741 | |||
742 | struct ivtv_mailbox_data enc_mbox; | ||
743 | struct ivtv_mailbox_data dec_mbox; | ||
744 | struct ivtv_api_cache api_cache[256]; /* Cached API Commands */ | ||
745 | |||
746 | u8 card_rev; | ||
747 | volatile void __iomem *enc_mem, *dec_mem, *reg_mem; | ||
748 | |||
749 | u32 pgm_info_offset; | ||
750 | u32 pgm_info_num; | ||
751 | u32 pgm_info_write_idx; | ||
752 | u32 pgm_info_read_idx; | ||
753 | struct v4l2_enc_idx_entry pgm_info[IVTV_MAX_PGM_INDEX]; | ||
754 | |||
755 | u64 mpg_data_received; | ||
756 | u64 vbi_data_inserted; | ||
757 | |||
758 | wait_queue_head_t cap_w; | ||
759 | /* when the next decoder event arrives this queue is woken up */ | ||
760 | wait_queue_head_t event_waitq; | ||
761 | /* when the next decoder vsync arrives this queue is woken up */ | ||
762 | wait_queue_head_t vsync_waitq; | ||
763 | /* when the current DMA is finished this queue is woken up */ | ||
764 | wait_queue_head_t dma_waitq; | ||
765 | |||
766 | /* OSD support */ | ||
767 | unsigned long osd_video_pbase; | ||
768 | int osd_global_alpha_state; /* 0=off : 1=on */ | ||
769 | int osd_local_alpha_state; /* 0=off : 1=on */ | ||
770 | int osd_color_key_state; /* 0=off : 1=on */ | ||
771 | u8 osd_global_alpha; /* Current global alpha */ | ||
772 | u32 osd_color_key; /* Current color key */ | ||
773 | u32 osd_pixelformat; /* Current pixel format */ | ||
774 | struct v4l2_rect osd_rect; /* Current OSD position and size */ | ||
775 | struct v4l2_rect main_rect; /* Current Main window position and size */ | ||
776 | |||
777 | u32 last_dec_timing[3]; /* Store last retrieved pts/scr/frame values */ | ||
778 | |||
779 | /* i2c */ | ||
780 | struct i2c_adapter i2c_adap; | ||
781 | struct i2c_algo_bit_data i2c_algo; | ||
782 | struct i2c_client i2c_client; | ||
783 | struct mutex i2c_bus_lock; | ||
784 | int i2c_state; | ||
785 | struct i2c_client *i2c_clients[I2C_CLIENTS_MAX]; | ||
786 | |||
787 | /* v4l2 and User settings */ | ||
788 | |||
789 | /* codec settings */ | ||
790 | struct cx2341x_mpeg_params params; | ||
791 | u32 audio_input; | ||
792 | u32 active_input; | ||
793 | u32 active_output; | ||
794 | v4l2_std_id std; | ||
795 | v4l2_std_id std_out; | ||
796 | v4l2_std_id tuner_std; /* The norm of the tuner (fixed) */ | ||
797 | u8 audio_stereo_mode; | ||
798 | u8 audio_bilingual_mode; | ||
799 | |||
800 | /* dualwatch */ | ||
801 | unsigned long dualwatch_jiffies; | ||
802 | u16 dualwatch_stereo_mode; | ||
803 | |||
804 | /* Digitizer type */ | ||
805 | int digitizer; /* 0x00EF = saa7114 0x00FO = saa7115 0x0106 = mic */ | ||
806 | |||
807 | u32 lastVsyncFrame; | ||
808 | |||
809 | struct yuv_playback_info yuv_info; | ||
810 | struct osd_info *osd_info; | ||
811 | }; | ||
812 | |||
813 | /* Globals */ | ||
814 | extern struct ivtv *ivtv_cards[]; | ||
815 | extern int ivtv_cards_active; | ||
816 | extern int ivtv_first_minor; | ||
817 | extern spinlock_t ivtv_cards_lock; | ||
818 | |||
819 | /*==============Prototypes==================*/ | ||
820 | |||
821 | /* Hardware/IRQ */ | ||
822 | void ivtv_set_irq_mask(struct ivtv *itv, u32 mask); | ||
823 | void ivtv_clear_irq_mask(struct ivtv *itv, u32 mask); | ||
824 | |||
825 | /* try to set output mode, return current mode. */ | ||
826 | int ivtv_set_output_mode(struct ivtv *itv, int mode); | ||
827 | |||
828 | /* return current output stream based on current mode */ | ||
829 | struct ivtv_stream *ivtv_get_output_stream(struct ivtv *itv); | ||
830 | |||
831 | /* Return non-zero if a signal is pending */ | ||
832 | int ivtv_sleep_timeout(int timeout, int intr); | ||
833 | |||
834 | /* Wait on queue, returns -EINTR if interrupted */ | ||
835 | int ivtv_waitq(wait_queue_head_t *waitq); | ||
836 | |||
837 | /* Read Hauppauge eeprom */ | ||
838 | struct tveeprom; /* forward reference */ | ||
839 | void ivtv_read_eeprom(struct ivtv *itv, struct tveeprom *tv); | ||
840 | |||
841 | /* This is a PCI post thing, where if the pci register is not read, then | ||
842 | the write doesn't always take effect right away. By reading back the | ||
843 | register any pending PCI writes will be performed (in order), and so | ||
844 | you can be sure that the writes are guaranteed to be done. | ||
845 | |||
846 | Rarely needed, only in some timing sensitive cases. | ||
847 | Apparently if this is not done some motherboards seem | ||
848 | to kill the firmware and get into the broken state until computer is | ||
849 | rebooted. */ | ||
850 | #define write_sync(val, reg) \ | ||
851 | do { writel(val, reg); readl(reg); } while (0) | ||
852 | |||
853 | #define read_reg(reg) readl(itv->reg_mem + (reg)) | ||
854 | #define write_reg(val, reg) writel(val, itv->reg_mem + (reg)) | ||
855 | #define write_reg_sync(val, reg) \ | ||
856 | do { write_reg(val, reg); read_reg(reg); } while (0) | ||
857 | |||
858 | #define read_enc(addr) readl(itv->enc_mem + (u32)(addr)) | ||
859 | #define write_enc(val, addr) writel(val, itv->enc_mem + (u32)(addr)) | ||
860 | #define write_enc_sync(val, addr) \ | ||
861 | do { write_enc(val, addr); read_enc(addr); } while (0) | ||
862 | |||
863 | #define read_dec(addr) readl(itv->dec_mem + (u32)(addr)) | ||
864 | #define write_dec(val, addr) writel(val, itv->dec_mem + (u32)(addr)) | ||
865 | #define write_dec_sync(val, addr) \ | ||
866 | do { write_dec(val, addr); read_dec(addr); } while (0) | ||
867 | |||
868 | #endif /* IVTV_DRIVER_H */ | ||
diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c new file mode 100644 index 000000000000..1637097ddec7 --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-fileops.c | |||
@@ -0,0 +1,921 @@ | |||
1 | /* | ||
2 | file operation functions | ||
3 | Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> | ||
4 | Copyright (C) 2004 Chris Kennedy <c@groovy.org> | ||
5 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2 of the License, or | ||
10 | (at your option) any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; if not, write to the Free Software | ||
19 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | */ | ||
21 | |||
22 | #include "ivtv-driver.h" | ||
23 | #include "ivtv-fileops.h" | ||
24 | #include "ivtv-i2c.h" | ||
25 | #include "ivtv-queue.h" | ||
26 | #include "ivtv-udma.h" | ||
27 | #include "ivtv-irq.h" | ||
28 | #include "ivtv-vbi.h" | ||
29 | #include "ivtv-mailbox.h" | ||
30 | #include "ivtv-audio.h" | ||
31 | #include "ivtv-streams.h" | ||
32 | #include "ivtv-yuv.h" | ||
33 | #include "ivtv-controls.h" | ||
34 | #include "ivtv-ioctl.h" | ||
35 | |||
36 | /* This function tries to claim the stream for a specific file descriptor. | ||
37 | If no one else is using this stream then the stream is claimed and | ||
38 | associated VBI streams are also automatically claimed. | ||
39 | Possible error returns: -EBUSY if someone else has claimed | ||
40 | the stream or 0 on success. */ | ||
41 | int ivtv_claim_stream(struct ivtv_open_id *id, int type) | ||
42 | { | ||
43 | struct ivtv *itv = id->itv; | ||
44 | struct ivtv_stream *s = &itv->streams[type]; | ||
45 | struct ivtv_stream *s_vbi; | ||
46 | int vbi_type; | ||
47 | |||
48 | if (test_and_set_bit(IVTV_F_S_CLAIMED, &s->s_flags)) { | ||
49 | /* someone already claimed this stream */ | ||
50 | if (s->id == id->open_id) { | ||
51 | /* yes, this file descriptor did. So that's OK. */ | ||
52 | return 0; | ||
53 | } | ||
54 | if (s->id == -1 && (type == IVTV_DEC_STREAM_TYPE_VBI || | ||
55 | type == IVTV_ENC_STREAM_TYPE_VBI)) { | ||
56 | /* VBI is handled already internally, now also assign | ||
57 | the file descriptor to this stream for external | ||
58 | reading of the stream. */ | ||
59 | s->id = id->open_id; | ||
60 | IVTV_DEBUG_INFO("Start Read VBI\n"); | ||
61 | return 0; | ||
62 | } | ||
63 | /* someone else is using this stream already */ | ||
64 | IVTV_DEBUG_INFO("Stream %d is busy\n", type); | ||
65 | return -EBUSY; | ||
66 | } | ||
67 | s->id = id->open_id; | ||
68 | if (type == IVTV_DEC_STREAM_TYPE_VBI) { | ||
69 | /* Enable reinsertion interrupt */ | ||
70 | ivtv_clear_irq_mask(itv, IVTV_IRQ_DEC_VBI_RE_INSERT); | ||
71 | } | ||
72 | |||
73 | /* IVTV_DEC_STREAM_TYPE_MPG needs to claim IVTV_DEC_STREAM_TYPE_VBI, | ||
74 | IVTV_ENC_STREAM_TYPE_MPG needs to claim IVTV_ENC_STREAM_TYPE_VBI | ||
75 | (provided VBI insertion is on and sliced VBI is selected), for all | ||
76 | other streams we're done */ | ||
77 | if (type == IVTV_DEC_STREAM_TYPE_MPG) { | ||
78 | vbi_type = IVTV_DEC_STREAM_TYPE_VBI; | ||
79 | } else if (type == IVTV_ENC_STREAM_TYPE_MPG && | ||
80 | itv->vbi.insert_mpeg && itv->vbi.sliced_in->service_set) { | ||
81 | vbi_type = IVTV_ENC_STREAM_TYPE_VBI; | ||
82 | } else { | ||
83 | return 0; | ||
84 | } | ||
85 | s_vbi = &itv->streams[vbi_type]; | ||
86 | |||
87 | if (!test_and_set_bit(IVTV_F_S_CLAIMED, &s_vbi->s_flags)) { | ||
88 | /* Enable reinsertion interrupt */ | ||
89 | if (vbi_type == IVTV_DEC_STREAM_TYPE_VBI) | ||
90 | ivtv_clear_irq_mask(itv, IVTV_IRQ_DEC_VBI_RE_INSERT); | ||
91 | } | ||
92 | /* mark that it is used internally */ | ||
93 | set_bit(IVTV_F_S_INTERNAL_USE, &s_vbi->s_flags); | ||
94 | return 0; | ||
95 | } | ||
96 | |||
97 | /* This function releases a previously claimed stream. It will take into | ||
98 | account associated VBI streams. */ | ||
99 | void ivtv_release_stream(struct ivtv_stream *s) | ||
100 | { | ||
101 | struct ivtv *itv = s->itv; | ||
102 | struct ivtv_stream *s_vbi; | ||
103 | |||
104 | s->id = -1; | ||
105 | if ((s->type == IVTV_DEC_STREAM_TYPE_VBI || s->type == IVTV_ENC_STREAM_TYPE_VBI) && | ||
106 | test_bit(IVTV_F_S_INTERNAL_USE, &s->s_flags)) { | ||
107 | /* this stream is still in use internally */ | ||
108 | return; | ||
109 | } | ||
110 | if (!test_and_clear_bit(IVTV_F_S_CLAIMED, &s->s_flags)) { | ||
111 | IVTV_DEBUG_WARN("Release stream %s not in use!\n", s->name); | ||
112 | return; | ||
113 | } | ||
114 | |||
115 | ivtv_flush_queues(s); | ||
116 | |||
117 | /* disable reinsertion interrupt */ | ||
118 | if (s->type == IVTV_DEC_STREAM_TYPE_VBI) | ||
119 | ivtv_set_irq_mask(itv, IVTV_IRQ_DEC_VBI_RE_INSERT); | ||
120 | |||
121 | /* IVTV_DEC_STREAM_TYPE_MPG needs to release IVTV_DEC_STREAM_TYPE_VBI, | ||
122 | IVTV_ENC_STREAM_TYPE_MPG needs to release IVTV_ENC_STREAM_TYPE_VBI, | ||
123 | for all other streams we're done */ | ||
124 | if (s->type == IVTV_DEC_STREAM_TYPE_MPG) | ||
125 | s_vbi = &itv->streams[IVTV_DEC_STREAM_TYPE_VBI]; | ||
126 | else if (s->type == IVTV_ENC_STREAM_TYPE_MPG) | ||
127 | s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; | ||
128 | else | ||
129 | return; | ||
130 | |||
131 | /* clear internal use flag */ | ||
132 | if (!test_and_clear_bit(IVTV_F_S_INTERNAL_USE, &s_vbi->s_flags)) { | ||
133 | /* was already cleared */ | ||
134 | return; | ||
135 | } | ||
136 | if (s_vbi->id != -1) { | ||
137 | /* VBI stream still claimed by a file descriptor */ | ||
138 | return; | ||
139 | } | ||
140 | /* disable reinsertion interrupt */ | ||
141 | if (s_vbi->type == IVTV_DEC_STREAM_TYPE_VBI) | ||
142 | ivtv_set_irq_mask(itv, IVTV_IRQ_DEC_VBI_RE_INSERT); | ||
143 | clear_bit(IVTV_F_S_CLAIMED, &s_vbi->s_flags); | ||
144 | ivtv_flush_queues(s_vbi); | ||
145 | } | ||
146 | |||
147 | static void ivtv_dualwatch(struct ivtv *itv) | ||
148 | { | ||
149 | struct v4l2_tuner vt; | ||
150 | u16 new_bitmap; | ||
151 | u16 new_stereo_mode; | ||
152 | const u16 stereo_mask = 0x0300; | ||
153 | const u16 dual = 0x0200; | ||
154 | |||
155 | new_stereo_mode = itv->params.audio_properties & stereo_mask; | ||
156 | memset(&vt, 0, sizeof(vt)); | ||
157 | ivtv_call_i2c_clients(itv, VIDIOC_G_TUNER, &vt); | ||
158 | if (vt.audmode == V4L2_TUNER_MODE_LANG1_LANG2 && (vt.rxsubchans & V4L2_TUNER_SUB_LANG2)) | ||
159 | new_stereo_mode = dual; | ||
160 | |||
161 | if (new_stereo_mode == itv->dualwatch_stereo_mode) | ||
162 | return; | ||
163 | |||
164 | new_bitmap = new_stereo_mode | (itv->params.audio_properties & ~stereo_mask); | ||
165 | |||
166 | IVTV_DEBUG_INFO("dualwatch: change stereo flag from 0x%x to 0x%x. new audio_bitmask=0x%ux\n", | ||
167 | itv->dualwatch_stereo_mode, new_stereo_mode, new_bitmap); | ||
168 | |||
169 | if (ivtv_vapi(itv, CX2341X_ENC_SET_AUDIO_PROPERTIES, 1, new_bitmap) == 0) { | ||
170 | itv->dualwatch_stereo_mode = new_stereo_mode; | ||
171 | return; | ||
172 | } | ||
173 | IVTV_DEBUG_INFO("dualwatch: changing stereo flag failed\n"); | ||
174 | } | ||
175 | |||
176 | static void ivtv_update_pgm_info(struct ivtv *itv) | ||
177 | { | ||
178 | u32 wr_idx = (read_enc(itv->pgm_info_offset) - itv->pgm_info_offset - 4) / 24; | ||
179 | int cnt; | ||
180 | int i = 0; | ||
181 | |||
182 | if (wr_idx >= itv->pgm_info_num) { | ||
183 | IVTV_DEBUG_WARN("Invalid PGM index %d (>= %d)\n", wr_idx, itv->pgm_info_num); | ||
184 | return; | ||
185 | } | ||
186 | cnt = (wr_idx + itv->pgm_info_num - itv->pgm_info_write_idx) % itv->pgm_info_num; | ||
187 | while (i < cnt) { | ||
188 | int idx = (itv->pgm_info_write_idx + i) % itv->pgm_info_num; | ||
189 | struct v4l2_enc_idx_entry *e = itv->pgm_info + idx; | ||
190 | u32 addr = itv->pgm_info_offset + 4 + idx * 24; | ||
191 | const int mapping[] = { V4L2_ENC_IDX_FRAME_P, V4L2_ENC_IDX_FRAME_I, V4L2_ENC_IDX_FRAME_B, 0 }; | ||
192 | |||
193 | e->offset = read_enc(addr + 4) + ((u64)read_enc(addr + 8) << 32); | ||
194 | if (e->offset > itv->mpg_data_received) { | ||
195 | break; | ||
196 | } | ||
197 | e->offset += itv->vbi_data_inserted; | ||
198 | e->length = read_enc(addr); | ||
199 | e->pts = read_enc(addr + 16) + ((u64)(read_enc(addr + 20) & 1) << 32); | ||
200 | e->flags = mapping[read_enc(addr + 12) & 3]; | ||
201 | i++; | ||
202 | } | ||
203 | itv->pgm_info_write_idx = (itv->pgm_info_write_idx + i) % itv->pgm_info_num; | ||
204 | } | ||
205 | |||
206 | static struct ivtv_buffer *ivtv_get_buffer(struct ivtv_stream *s, int non_block, int *err) | ||
207 | { | ||
208 | struct ivtv *itv = s->itv; | ||
209 | struct ivtv_stream *s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; | ||
210 | struct ivtv_buffer *buf; | ||
211 | DEFINE_WAIT(wait); | ||
212 | |||
213 | *err = 0; | ||
214 | while (1) { | ||
215 | if (s->type == IVTV_ENC_STREAM_TYPE_MPG) { | ||
216 | /* Process pending program info updates and pending VBI data */ | ||
217 | ivtv_update_pgm_info(itv); | ||
218 | |||
219 | if (jiffies - itv->dualwatch_jiffies > HZ) { | ||
220 | itv->dualwatch_jiffies = jiffies; | ||
221 | ivtv_dualwatch(itv); | ||
222 | } | ||
223 | |||
224 | if (test_bit(IVTV_F_S_INTERNAL_USE, &s_vbi->s_flags) && | ||
225 | !test_bit(IVTV_F_S_APPL_IO, &s_vbi->s_flags)) { | ||
226 | while ((buf = ivtv_dequeue(s_vbi, &s_vbi->q_full))) { | ||
227 | /* byteswap and process VBI data */ | ||
228 | ivtv_process_vbi_data(itv, buf, s_vbi->dma_pts, s_vbi->type); | ||
229 | ivtv_enqueue(s_vbi, buf, &s_vbi->q_free); | ||
230 | } | ||
231 | } | ||
232 | buf = &itv->vbi.sliced_mpeg_buf; | ||
233 | if (buf->readpos != buf->bytesused) { | ||
234 | return buf; | ||
235 | } | ||
236 | } | ||
237 | |||
238 | /* do we have leftover data? */ | ||
239 | buf = ivtv_dequeue(s, &s->q_io); | ||
240 | if (buf) | ||
241 | return buf; | ||
242 | |||
243 | /* do we have new data? */ | ||
244 | buf = ivtv_dequeue(s, &s->q_full); | ||
245 | if (buf) { | ||
246 | if (!test_and_clear_bit(IVTV_F_B_NEED_BUF_SWAP, &buf->b_flags)) | ||
247 | return buf; | ||
248 | if (s->type == IVTV_ENC_STREAM_TYPE_MPG) | ||
249 | /* byteswap MPG data */ | ||
250 | ivtv_buf_swap(buf); | ||
251 | else if (s->type != IVTV_DEC_STREAM_TYPE_VBI) { | ||
252 | /* byteswap and process VBI data */ | ||
253 | ivtv_process_vbi_data(itv, buf, s->dma_pts, s->type); | ||
254 | } | ||
255 | return buf; | ||
256 | } | ||
257 | /* return if file was opened with O_NONBLOCK */ | ||
258 | if (non_block) { | ||
259 | *err = -EAGAIN; | ||
260 | return NULL; | ||
261 | } | ||
262 | |||
263 | /* return if end of stream */ | ||
264 | if (s->type != IVTV_DEC_STREAM_TYPE_VBI && !test_bit(IVTV_F_S_STREAMING, &s->s_flags)) { | ||
265 | clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags); | ||
266 | IVTV_DEBUG_INFO("EOS %s\n", s->name); | ||
267 | return NULL; | ||
268 | } | ||
269 | |||
270 | /* wait for more data to arrive */ | ||
271 | prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE); | ||
272 | /* New buffers might have become available before we were added to the waitqueue */ | ||
273 | if (!s->q_full.buffers) | ||
274 | schedule(); | ||
275 | finish_wait(&s->waitq, &wait); | ||
276 | if (signal_pending(current)) { | ||
277 | /* return if a signal was received */ | ||
278 | IVTV_DEBUG_INFO("User stopped %s\n", s->name); | ||
279 | *err = -EINTR; | ||
280 | return NULL; | ||
281 | } | ||
282 | } | ||
283 | } | ||
284 | |||
285 | static void ivtv_setup_sliced_vbi_buf(struct ivtv *itv) | ||
286 | { | ||
287 | int idx = itv->vbi.inserted_frame % IVTV_VBI_FRAMES; | ||
288 | |||
289 | itv->vbi.sliced_mpeg_buf.buf = itv->vbi.sliced_mpeg_data[idx]; | ||
290 | itv->vbi.sliced_mpeg_buf.bytesused = itv->vbi.sliced_mpeg_size[idx]; | ||
291 | itv->vbi.sliced_mpeg_buf.readpos = 0; | ||
292 | } | ||
293 | |||
294 | static size_t ivtv_copy_buf_to_user(struct ivtv_stream *s, struct ivtv_buffer *buf, | ||
295 | char __user *ubuf, size_t ucount) | ||
296 | { | ||
297 | struct ivtv *itv = s->itv; | ||
298 | size_t len = buf->bytesused - buf->readpos; | ||
299 | |||
300 | if (len > ucount) len = ucount; | ||
301 | if (itv->vbi.insert_mpeg && s->type == IVTV_ENC_STREAM_TYPE_MPG && | ||
302 | itv->vbi.sliced_in->service_set && buf != &itv->vbi.sliced_mpeg_buf) { | ||
303 | const char *start = buf->buf + buf->readpos; | ||
304 | const char *p = start + 1; | ||
305 | const u8 *q; | ||
306 | u8 ch = itv->search_pack_header ? 0xba : 0xe0; | ||
307 | int stuffing, i; | ||
308 | |||
309 | while (start + len > p && (q = memchr(p, 0, start + len - p))) { | ||
310 | p = q + 1; | ||
311 | if ((char *)q + 15 >= buf->buf + buf->bytesused || | ||
312 | q[1] != 0 || q[2] != 1 || q[3] != ch) { | ||
313 | continue; | ||
314 | } | ||
315 | if (!itv->search_pack_header) { | ||
316 | if ((q[6] & 0xc0) != 0x80) | ||
317 | continue; | ||
318 | if (((q[7] & 0xc0) == 0x80 && (q[9] & 0xf0) == 0x20) || | ||
319 | ((q[7] & 0xc0) == 0xc0 && (q[9] & 0xf0) == 0x30)) { | ||
320 | ch = 0xba; | ||
321 | itv->search_pack_header = 1; | ||
322 | p = q + 9; | ||
323 | } | ||
324 | continue; | ||
325 | } | ||
326 | stuffing = q[13] & 7; | ||
327 | /* all stuffing bytes must be 0xff */ | ||
328 | for (i = 0; i < stuffing; i++) | ||
329 | if (q[14 + i] != 0xff) | ||
330 | break; | ||
331 | if (i == stuffing && (q[4] & 0xc4) == 0x44 && (q[12] & 3) == 3 && | ||
332 | q[14 + stuffing] == 0 && q[15 + stuffing] == 0 && | ||
333 | q[16 + stuffing] == 1) { | ||
334 | itv->search_pack_header = 0; | ||
335 | len = (char *)q - start; | ||
336 | ivtv_setup_sliced_vbi_buf(itv); | ||
337 | break; | ||
338 | } | ||
339 | } | ||
340 | } | ||
341 | if (copy_to_user(ubuf, (u8 *)buf->buf + buf->readpos, len)) { | ||
342 | IVTV_DEBUG_WARN("copy %zd bytes to user failed for %s\n", len, s->name); | ||
343 | return -EFAULT; | ||
344 | } | ||
345 | /*IVTV_INFO("copied %lld %d %d %d %d %d vbi %d\n", itv->mpg_data_received, len, ucount, | ||
346 | buf->readpos, buf->bytesused, buf->bytesused - buf->readpos - len, | ||
347 | buf == &itv->vbi.sliced_mpeg_buf); */ | ||
348 | buf->readpos += len; | ||
349 | if (s->type == IVTV_ENC_STREAM_TYPE_MPG && buf != &itv->vbi.sliced_mpeg_buf) | ||
350 | itv->mpg_data_received += len; | ||
351 | return len; | ||
352 | } | ||
353 | |||
354 | static ssize_t ivtv_read(struct ivtv_stream *s, char __user *ubuf, size_t tot_count, int non_block) | ||
355 | { | ||
356 | struct ivtv *itv = s->itv; | ||
357 | size_t tot_written = 0; | ||
358 | int single_frame = 0; | ||
359 | |||
360 | if (atomic_read(&itv->capturing) == 0 && s->id == -1) { | ||
361 | /* shouldn't happen */ | ||
362 | IVTV_DEBUG_WARN("Stream %s not initialized before read\n", s->name); | ||
363 | return -EIO; | ||
364 | } | ||
365 | |||
366 | /* Each VBI buffer is one frame, the v4l2 API says that for VBI the frames should | ||
367 | arrive one-by-one, so make sure we never output more than one VBI frame at a time */ | ||
368 | if (s->type == IVTV_DEC_STREAM_TYPE_VBI || | ||
369 | (s->type == IVTV_ENC_STREAM_TYPE_VBI && itv->vbi.sliced_in->service_set)) | ||
370 | single_frame = 1; | ||
371 | |||
372 | for (;;) { | ||
373 | struct ivtv_buffer *buf; | ||
374 | int rc; | ||
375 | |||
376 | buf = ivtv_get_buffer(s, non_block, &rc); | ||
377 | if (buf == NULL && rc == -EAGAIN && tot_written) | ||
378 | break; | ||
379 | if (buf == NULL) | ||
380 | return rc; | ||
381 | rc = ivtv_copy_buf_to_user(s, buf, ubuf + tot_written, tot_count - tot_written); | ||
382 | if (buf != &itv->vbi.sliced_mpeg_buf) { | ||
383 | ivtv_enqueue(s, buf, (buf->readpos == buf->bytesused) ? &s->q_free : &s->q_io); | ||
384 | } | ||
385 | else if (buf->readpos == buf->bytesused) { | ||
386 | int idx = itv->vbi.inserted_frame % IVTV_VBI_FRAMES; | ||
387 | itv->vbi.sliced_mpeg_size[idx] = 0; | ||
388 | itv->vbi.inserted_frame++; | ||
389 | itv->vbi_data_inserted += buf->bytesused; | ||
390 | } | ||
391 | if (rc < 0) | ||
392 | return rc; | ||
393 | tot_written += rc; | ||
394 | |||
395 | if (tot_written == tot_count || single_frame) | ||
396 | break; | ||
397 | } | ||
398 | return tot_written; | ||
399 | } | ||
400 | |||
401 | static ssize_t ivtv_read_pos(struct ivtv_stream *s, char __user *ubuf, size_t count, | ||
402 | loff_t *pos, int non_block) | ||
403 | { | ||
404 | ssize_t rc = count ? ivtv_read(s, ubuf, count, non_block) : 0; | ||
405 | struct ivtv *itv = s->itv; | ||
406 | |||
407 | IVTV_DEBUG_INFO("read %zd from %s, got %zd\n", count, s->name, rc); | ||
408 | if (rc > 0) | ||
409 | pos += rc; | ||
410 | return rc; | ||
411 | } | ||
412 | |||
413 | int ivtv_start_capture(struct ivtv_open_id *id) | ||
414 | { | ||
415 | struct ivtv *itv = id->itv; | ||
416 | struct ivtv_stream *s = &itv->streams[id->type]; | ||
417 | struct ivtv_stream *s_vbi; | ||
418 | |||
419 | if (s->type == IVTV_ENC_STREAM_TYPE_RAD || | ||
420 | s->type == IVTV_DEC_STREAM_TYPE_MPG || | ||
421 | s->type == IVTV_DEC_STREAM_TYPE_YUV || | ||
422 | s->type == IVTV_DEC_STREAM_TYPE_VOUT) { | ||
423 | /* you cannot read from these stream types. */ | ||
424 | return -EPERM; | ||
425 | } | ||
426 | |||
427 | /* Try to claim this stream. */ | ||
428 | if (ivtv_claim_stream(id, s->type)) | ||
429 | return -EBUSY; | ||
430 | |||
431 | /* This stream does not need to start capturing */ | ||
432 | if (s->type == IVTV_DEC_STREAM_TYPE_VBI) { | ||
433 | set_bit(IVTV_F_S_APPL_IO, &s->s_flags); | ||
434 | return 0; | ||
435 | } | ||
436 | |||
437 | /* If capture is already in progress, then we also have to | ||
438 | do nothing extra. */ | ||
439 | if (test_bit(IVTV_F_S_STREAMOFF, &s->s_flags) || test_and_set_bit(IVTV_F_S_STREAMING, &s->s_flags)) { | ||
440 | set_bit(IVTV_F_S_APPL_IO, &s->s_flags); | ||
441 | return 0; | ||
442 | } | ||
443 | |||
444 | /* Start VBI capture if required */ | ||
445 | s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; | ||
446 | if (s->type == IVTV_ENC_STREAM_TYPE_MPG && | ||
447 | test_bit(IVTV_F_S_INTERNAL_USE, &s_vbi->s_flags) && | ||
448 | !test_and_set_bit(IVTV_F_S_STREAMING, &s_vbi->s_flags)) { | ||
449 | /* Note: the IVTV_ENC_STREAM_TYPE_VBI is claimed | ||
450 | automatically when the MPG stream is claimed. | ||
451 | We only need to start the VBI capturing. */ | ||
452 | if (ivtv_start_v4l2_encode_stream(s_vbi)) { | ||
453 | IVTV_DEBUG_WARN("VBI capture start failed\n"); | ||
454 | |||
455 | /* Failure, clean up and return an error */ | ||
456 | clear_bit(IVTV_F_S_STREAMING, &s_vbi->s_flags); | ||
457 | clear_bit(IVTV_F_S_STREAMING, &s->s_flags); | ||
458 | /* also releases the associated VBI stream */ | ||
459 | ivtv_release_stream(s); | ||
460 | return -EIO; | ||
461 | } | ||
462 | IVTV_DEBUG_INFO("VBI insertion started\n"); | ||
463 | } | ||
464 | |||
465 | /* Tell the card to start capturing */ | ||
466 | if (!ivtv_start_v4l2_encode_stream(s)) { | ||
467 | /* We're done */ | ||
468 | set_bit(IVTV_F_S_APPL_IO, &s->s_flags); | ||
469 | /* Resume a possibly paused encoder */ | ||
470 | if (test_and_clear_bit(IVTV_F_I_ENC_PAUSED, &itv->i_flags)) | ||
471 | ivtv_vapi(itv, CX2341X_ENC_PAUSE_ENCODER, 1, 1); | ||
472 | return 0; | ||
473 | } | ||
474 | |||
475 | /* failure, clean up */ | ||
476 | IVTV_DEBUG_WARN("Failed to start capturing for stream %s\n", s->name); | ||
477 | |||
478 | /* Note: the IVTV_ENC_STREAM_TYPE_VBI is released | ||
479 | automatically when the MPG stream is released. | ||
480 | We only need to stop the VBI capturing. */ | ||
481 | if (s->type == IVTV_ENC_STREAM_TYPE_MPG && | ||
482 | test_bit(IVTV_F_S_STREAMING, &s_vbi->s_flags)) { | ||
483 | ivtv_stop_v4l2_encode_stream(s_vbi, 0); | ||
484 | clear_bit(IVTV_F_S_STREAMING, &s_vbi->s_flags); | ||
485 | } | ||
486 | clear_bit(IVTV_F_S_STREAMING, &s->s_flags); | ||
487 | ivtv_release_stream(s); | ||
488 | return -EIO; | ||
489 | } | ||
490 | |||
491 | ssize_t ivtv_v4l2_read(struct file * filp, char __user *buf, size_t count, loff_t * pos) | ||
492 | { | ||
493 | struct ivtv_open_id *id = filp->private_data; | ||
494 | struct ivtv *itv = id->itv; | ||
495 | struct ivtv_stream *s = &itv->streams[id->type]; | ||
496 | int rc; | ||
497 | |||
498 | IVTV_DEBUG_IOCTL("read %zd bytes from %s\n", count, s->name); | ||
499 | |||
500 | rc = ivtv_start_capture(id); | ||
501 | if (rc) | ||
502 | return rc; | ||
503 | return ivtv_read_pos(s, buf, count, pos, filp->f_flags & O_NONBLOCK); | ||
504 | } | ||
505 | |||
506 | int ivtv_start_decoding(struct ivtv_open_id *id, int speed) | ||
507 | { | ||
508 | struct ivtv *itv = id->itv; | ||
509 | struct ivtv_stream *s = &itv->streams[id->type]; | ||
510 | |||
511 | if (atomic_read(&itv->decoding) == 0) { | ||
512 | if (ivtv_claim_stream(id, s->type)) { | ||
513 | /* someone else is using this stream already */ | ||
514 | IVTV_DEBUG_WARN("start decode, stream already claimed\n"); | ||
515 | return -EBUSY; | ||
516 | } | ||
517 | ivtv_start_v4l2_decode_stream(s, 0); | ||
518 | } | ||
519 | if (s->type == IVTV_DEC_STREAM_TYPE_MPG) | ||
520 | return ivtv_set_speed(itv, speed); | ||
521 | return 0; | ||
522 | } | ||
523 | |||
524 | ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t count, loff_t *pos) | ||
525 | { | ||
526 | struct ivtv_open_id *id = filp->private_data; | ||
527 | struct ivtv *itv = id->itv; | ||
528 | struct ivtv_stream *s = &itv->streams[id->type]; | ||
529 | struct ivtv_buffer *buf; | ||
530 | struct ivtv_queue q; | ||
531 | int bytes_written = 0; | ||
532 | int mode; | ||
533 | int rc; | ||
534 | DEFINE_WAIT(wait); | ||
535 | |||
536 | IVTV_DEBUG_IOCTL("write %zd bytes to %s\n", count, s->name); | ||
537 | |||
538 | if (s->type != IVTV_DEC_STREAM_TYPE_MPG && | ||
539 | s->type != IVTV_DEC_STREAM_TYPE_YUV && | ||
540 | s->type != IVTV_DEC_STREAM_TYPE_VOUT) | ||
541 | /* not decoder streams */ | ||
542 | return -EPERM; | ||
543 | |||
544 | /* Try to claim this stream */ | ||
545 | if (ivtv_claim_stream(id, s->type)) | ||
546 | return -EBUSY; | ||
547 | |||
548 | /* This stream does not need to start any decoding */ | ||
549 | if (s->type == IVTV_DEC_STREAM_TYPE_VOUT) { | ||
550 | set_bit(IVTV_F_S_APPL_IO, &s->s_flags); | ||
551 | return ivtv_write_vbi(itv, user_buf, count); | ||
552 | } | ||
553 | |||
554 | mode = s->type == IVTV_DEC_STREAM_TYPE_MPG ? OUT_MPG : OUT_YUV; | ||
555 | |||
556 | if (ivtv_set_output_mode(itv, mode) != mode) { | ||
557 | ivtv_release_stream(s); | ||
558 | return -EBUSY; | ||
559 | } | ||
560 | ivtv_queue_init(&q); | ||
561 | set_bit(IVTV_F_S_APPL_IO, &s->s_flags); | ||
562 | |||
563 | retry: | ||
564 | for (;;) { | ||
565 | /* Gather buffers */ | ||
566 | while (q.length - q.bytesused < count && (buf = ivtv_dequeue(s, &s->q_io))) | ||
567 | ivtv_enqueue(s, buf, &q); | ||
568 | while (q.length - q.bytesused < count && (buf = ivtv_dequeue(s, &s->q_free))) { | ||
569 | ivtv_enqueue(s, buf, &q); | ||
570 | } | ||
571 | if (q.buffers) | ||
572 | break; | ||
573 | if (filp->f_flags & O_NONBLOCK) | ||
574 | return -EAGAIN; | ||
575 | prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE); | ||
576 | /* New buffers might have become free before we were added to the waitqueue */ | ||
577 | if (!s->q_free.buffers) | ||
578 | schedule(); | ||
579 | finish_wait(&s->waitq, &wait); | ||
580 | if (signal_pending(current)) { | ||
581 | IVTV_DEBUG_INFO("User stopped %s\n", s->name); | ||
582 | return -EINTR; | ||
583 | } | ||
584 | } | ||
585 | |||
586 | /* copy user data into buffers */ | ||
587 | while ((buf = ivtv_dequeue(s, &q))) { | ||
588 | /* Make sure we really got all the user data */ | ||
589 | rc = ivtv_buf_copy_from_user(s, buf, user_buf, count); | ||
590 | |||
591 | if (rc < 0) { | ||
592 | ivtv_queue_move(s, &q, NULL, &s->q_free, 0); | ||
593 | return rc; | ||
594 | } | ||
595 | user_buf += rc; | ||
596 | count -= rc; | ||
597 | bytes_written += rc; | ||
598 | |||
599 | if (buf->bytesused != s->buf_size) { | ||
600 | /* incomplete, leave in q_io for next time */ | ||
601 | ivtv_enqueue(s, buf, &s->q_io); | ||
602 | break; | ||
603 | } | ||
604 | /* Byteswap MPEG buffer */ | ||
605 | if (s->type == IVTV_DEC_STREAM_TYPE_MPG) | ||
606 | ivtv_buf_swap(buf); | ||
607 | ivtv_enqueue(s, buf, &s->q_full); | ||
608 | } | ||
609 | |||
610 | /* Start decoder (returns 0 if already started) */ | ||
611 | rc = ivtv_start_decoding(id, itv->speed); | ||
612 | if (rc) { | ||
613 | IVTV_DEBUG_WARN("Failed start decode stream %s\n", s->name); | ||
614 | |||
615 | /* failure, clean up */ | ||
616 | clear_bit(IVTV_F_S_STREAMING, &s->s_flags); | ||
617 | clear_bit(IVTV_F_S_APPL_IO, &s->s_flags); | ||
618 | return rc; | ||
619 | } | ||
620 | if (test_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags)) { | ||
621 | if (s->q_full.length >= itv->dma_data_req_size) { | ||
622 | int got_sig; | ||
623 | |||
624 | prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE); | ||
625 | while (!(got_sig = signal_pending(current)) && | ||
626 | test_bit(IVTV_F_S_DMA_PENDING, &s->s_flags)) { | ||
627 | schedule(); | ||
628 | } | ||
629 | finish_wait(&itv->dma_waitq, &wait); | ||
630 | if (got_sig) { | ||
631 | IVTV_DEBUG_INFO("User interrupted %s\n", s->name); | ||
632 | return -EINTR; | ||
633 | } | ||
634 | |||
635 | clear_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags); | ||
636 | ivtv_queue_move(s, &s->q_full, NULL, &s->q_predma, itv->dma_data_req_size); | ||
637 | ivtv_dma_stream_dec_prepare(s, itv->dma_data_req_offset + IVTV_DECODER_OFFSET, 1); | ||
638 | } | ||
639 | } | ||
640 | /* more user data is available, wait until buffers become free | ||
641 | to transfer the rest. */ | ||
642 | if (count && !(filp->f_flags & O_NONBLOCK)) | ||
643 | goto retry; | ||
644 | IVTV_DEBUG_INFO("Wrote %d bytes to %s (%d)\n", bytes_written, s->name, s->q_full.bytesused); | ||
645 | return bytes_written; | ||
646 | } | ||
647 | |||
648 | unsigned int ivtv_v4l2_dec_poll(struct file *filp, poll_table *wait) | ||
649 | { | ||
650 | struct ivtv_open_id *id = filp->private_data; | ||
651 | struct ivtv *itv = id->itv; | ||
652 | struct ivtv_stream *s = &itv->streams[id->type]; | ||
653 | int res = 0; | ||
654 | |||
655 | /* add stream's waitq to the poll list */ | ||
656 | poll_wait(filp, &s->waitq, wait); | ||
657 | |||
658 | set_bit(IVTV_F_I_EV_VSYNC_ENABLED, &itv->i_flags); | ||
659 | if (test_bit(IVTV_F_I_EV_VSYNC, &itv->i_flags) || | ||
660 | test_bit(IVTV_F_I_EV_DEC_STOPPED, &itv->i_flags)) | ||
661 | res = POLLPRI; | ||
662 | |||
663 | /* Allow write if buffers are available for writing */ | ||
664 | if (s->q_free.buffers) | ||
665 | res |= POLLOUT | POLLWRNORM; | ||
666 | return res; | ||
667 | } | ||
668 | |||
669 | unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table * wait) | ||
670 | { | ||
671 | struct ivtv_open_id *id = filp->private_data; | ||
672 | struct ivtv *itv = id->itv; | ||
673 | struct ivtv_stream *s = &itv->streams[id->type]; | ||
674 | int eof = test_bit(IVTV_F_S_STREAMOFF, &s->s_flags); | ||
675 | |||
676 | /* Start a capture if there is none */ | ||
677 | if (!eof && !test_bit(IVTV_F_S_STREAMING, &s->s_flags)) { | ||
678 | int rc = ivtv_start_capture(id); | ||
679 | |||
680 | if (rc) { | ||
681 | IVTV_DEBUG_INFO("Could not start capture for %s (%d)\n", | ||
682 | s->name, rc); | ||
683 | return POLLERR; | ||
684 | } | ||
685 | } | ||
686 | |||
687 | /* add stream's waitq to the poll list */ | ||
688 | poll_wait(filp, &s->waitq, wait); | ||
689 | |||
690 | if (eof || s->q_full.length) | ||
691 | return POLLIN | POLLRDNORM; | ||
692 | return 0; | ||
693 | } | ||
694 | |||
695 | void ivtv_stop_capture(struct ivtv_open_id *id, int gop_end) | ||
696 | { | ||
697 | struct ivtv *itv = id->itv; | ||
698 | struct ivtv_stream *s = &itv->streams[id->type]; | ||
699 | |||
700 | IVTV_DEBUG_IOCTL("close() of %s\n", s->name); | ||
701 | |||
702 | /* 'Unclaim' this stream */ | ||
703 | |||
704 | /* Stop capturing */ | ||
705 | if (test_bit(IVTV_F_S_STREAMING, &s->s_flags)) { | ||
706 | struct ivtv_stream *s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; | ||
707 | |||
708 | IVTV_DEBUG_INFO("close stopping capture\n"); | ||
709 | /* Special case: a running VBI capture for VBI insertion | ||
710 | in the mpeg stream. Need to stop that too. */ | ||
711 | if (id->type == IVTV_ENC_STREAM_TYPE_MPG && | ||
712 | test_bit(IVTV_F_S_STREAMING, &s_vbi->s_flags) && | ||
713 | !test_bit(IVTV_F_S_APPL_IO, &s_vbi->s_flags)) { | ||
714 | IVTV_DEBUG_INFO("close stopping embedded VBI capture\n"); | ||
715 | ivtv_stop_v4l2_encode_stream(s_vbi, 0); | ||
716 | } | ||
717 | if ((id->type == IVTV_DEC_STREAM_TYPE_VBI || | ||
718 | id->type == IVTV_ENC_STREAM_TYPE_VBI) && | ||
719 | test_bit(IVTV_F_S_INTERNAL_USE, &s->s_flags)) { | ||
720 | /* Also used internally, don't stop capturing */ | ||
721 | s->id = -1; | ||
722 | } | ||
723 | else { | ||
724 | ivtv_stop_v4l2_encode_stream(s, gop_end); | ||
725 | } | ||
726 | } | ||
727 | clear_bit(IVTV_F_S_APPL_IO, &s->s_flags); | ||
728 | clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags); | ||
729 | |||
730 | ivtv_release_stream(s); | ||
731 | } | ||
732 | |||
733 | static void ivtv_stop_decoding(struct ivtv_open_id *id, int flags, u64 pts) | ||
734 | { | ||
735 | struct ivtv *itv = id->itv; | ||
736 | struct ivtv_stream *s = &itv->streams[id->type]; | ||
737 | |||
738 | IVTV_DEBUG_IOCTL("close() of %s\n", s->name); | ||
739 | |||
740 | /* Stop decoding */ | ||
741 | if (test_bit(IVTV_F_S_STREAMING, &s->s_flags)) { | ||
742 | IVTV_DEBUG_INFO("close stopping decode\n"); | ||
743 | |||
744 | ivtv_stop_v4l2_decode_stream(s, flags, pts); | ||
745 | } | ||
746 | clear_bit(IVTV_F_S_APPL_IO, &s->s_flags); | ||
747 | clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags); | ||
748 | if (id->type == IVTV_DEC_STREAM_TYPE_YUV && test_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags)) { | ||
749 | /* Restore registers we've changed & clean up any mess we've made */ | ||
750 | ivtv_yuv_close(itv); | ||
751 | } | ||
752 | if (s->type == IVTV_DEC_STREAM_TYPE_YUV && itv->output_mode == OUT_YUV) | ||
753 | itv->output_mode = OUT_NONE; | ||
754 | else if (s->type == IVTV_DEC_STREAM_TYPE_MPG && itv->output_mode == OUT_MPG) | ||
755 | itv->output_mode = OUT_NONE; | ||
756 | |||
757 | itv->speed = 0; | ||
758 | ivtv_release_stream(s); | ||
759 | } | ||
760 | |||
761 | int ivtv_v4l2_close(struct inode *inode, struct file *filp) | ||
762 | { | ||
763 | struct ivtv_open_id *id = filp->private_data; | ||
764 | struct ivtv *itv = id->itv; | ||
765 | struct ivtv_stream *s = &itv->streams[id->type]; | ||
766 | |||
767 | IVTV_DEBUG_IOCTL("close() of %s\n", s->name); | ||
768 | |||
769 | v4l2_prio_close(&itv->prio, &id->prio); | ||
770 | |||
771 | /* Easy case first: this stream was never claimed by us */ | ||
772 | if (s->id != id->open_id) { | ||
773 | kfree(id); | ||
774 | return 0; | ||
775 | } | ||
776 | |||
777 | /* 'Unclaim' this stream */ | ||
778 | |||
779 | /* Stop radio */ | ||
780 | if (id->type == IVTV_ENC_STREAM_TYPE_RAD) { | ||
781 | /* Closing radio device, return to TV mode */ | ||
782 | ivtv_mute(itv); | ||
783 | /* Mark that the radio is no longer in use */ | ||
784 | clear_bit(IVTV_F_I_RADIO_USER, &itv->i_flags); | ||
785 | /* Switch tuner to TV */ | ||
786 | ivtv_call_i2c_clients(itv, VIDIOC_S_STD, &itv->std); | ||
787 | /* Select correct audio input (i.e. TV tuner or Line in) */ | ||
788 | ivtv_audio_set_io(itv); | ||
789 | /* Done! Unmute and continue. */ | ||
790 | ivtv_unmute(itv); | ||
791 | ivtv_release_stream(s); | ||
792 | } else if (s->type >= IVTV_DEC_STREAM_TYPE_MPG) { | ||
793 | ivtv_stop_decoding(id, VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY, 0); | ||
794 | } else { | ||
795 | ivtv_stop_capture(id, 0); | ||
796 | } | ||
797 | kfree(id); | ||
798 | return 0; | ||
799 | } | ||
800 | |||
801 | int ivtv_v4l2_open(struct inode *inode, struct file *filp) | ||
802 | { | ||
803 | int x, y = 0; | ||
804 | struct ivtv_open_id *item; | ||
805 | struct ivtv *itv = NULL; | ||
806 | struct ivtv_stream *s = NULL; | ||
807 | int minor = MINOR(inode->i_rdev); | ||
808 | |||
809 | /* Find which card this open was on */ | ||
810 | spin_lock(&ivtv_cards_lock); | ||
811 | for (x = 0; itv == NULL && x < ivtv_cards_active; x++) { | ||
812 | /* find out which stream this open was on */ | ||
813 | for (y = 0; y < IVTV_MAX_STREAMS; y++) { | ||
814 | s = &ivtv_cards[x]->streams[y]; | ||
815 | if (s->v4l2dev && s->v4l2dev->minor == minor) { | ||
816 | itv = ivtv_cards[x]; | ||
817 | break; | ||
818 | } | ||
819 | } | ||
820 | } | ||
821 | spin_unlock(&ivtv_cards_lock); | ||
822 | |||
823 | if (itv == NULL) { | ||
824 | /* Couldn't find a device registered | ||
825 | on that minor, shouldn't happen! */ | ||
826 | printk(KERN_WARNING "ivtv: no ivtv device found on minor %d\n", minor); | ||
827 | return -ENXIO; | ||
828 | } | ||
829 | |||
830 | if (y == IVTV_DEC_STREAM_TYPE_MPG && | ||
831 | test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_YUV].s_flags)) | ||
832 | return -EBUSY; | ||
833 | |||
834 | if (y == IVTV_DEC_STREAM_TYPE_YUV && | ||
835 | test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_MPG].s_flags)) | ||
836 | return -EBUSY; | ||
837 | |||
838 | if (y == IVTV_DEC_STREAM_TYPE_YUV) { | ||
839 | if (read_reg(0x82c) == 0) { | ||
840 | IVTV_ERR("Tried to open YUV output device but need to send data to mpeg decoder before it can be used\n"); | ||
841 | /* return -ENODEV; */ | ||
842 | } | ||
843 | ivtv_udma_alloc(itv); | ||
844 | } | ||
845 | |||
846 | /* Allocate memory */ | ||
847 | item = kmalloc(sizeof(struct ivtv_open_id), GFP_KERNEL); | ||
848 | if (NULL == item) { | ||
849 | IVTV_DEBUG_WARN("nomem on v4l2 open\n"); | ||
850 | return -ENOMEM; | ||
851 | } | ||
852 | item->itv = itv; | ||
853 | item->type = y; | ||
854 | v4l2_prio_open(&itv->prio, &item->prio); | ||
855 | |||
856 | item->open_id = itv->open_id++; | ||
857 | filp->private_data = item; | ||
858 | |||
859 | if (item->type == IVTV_ENC_STREAM_TYPE_RAD) { | ||
860 | /* Try to claim this stream */ | ||
861 | if (ivtv_claim_stream(item, item->type)) { | ||
862 | /* No, it's already in use */ | ||
863 | kfree(item); | ||
864 | return -EBUSY; | ||
865 | } | ||
866 | |||
867 | /* We have the radio */ | ||
868 | ivtv_mute(itv); | ||
869 | /* Switch tuner to radio */ | ||
870 | ivtv_call_i2c_clients(itv, AUDC_SET_RADIO, NULL); | ||
871 | /* Mark that the radio is being used. */ | ||
872 | set_bit(IVTV_F_I_RADIO_USER, &itv->i_flags); | ||
873 | /* Select the correct audio input (i.e. radio tuner) */ | ||
874 | ivtv_audio_set_io(itv); | ||
875 | /* Done! Unmute and continue. */ | ||
876 | ivtv_unmute(itv); | ||
877 | } | ||
878 | |||
879 | /* YUV or MPG Decoding Mode? */ | ||
880 | if (y == IVTV_DEC_STREAM_TYPE_MPG) | ||
881 | clear_bit(IVTV_F_I_DEC_YUV, &itv->i_flags); | ||
882 | else if (y == IVTV_DEC_STREAM_TYPE_YUV) | ||
883 | { | ||
884 | set_bit(IVTV_F_I_DEC_YUV, &itv->i_flags); | ||
885 | } | ||
886 | |||
887 | return 0; | ||
888 | } | ||
889 | |||
890 | void ivtv_mute(struct ivtv *itv) | ||
891 | { | ||
892 | struct v4l2_control ctrl = { V4L2_CID_AUDIO_MUTE, 1 }; | ||
893 | |||
894 | /* Mute sound to avoid pop */ | ||
895 | ivtv_control_ioctls(itv, VIDIOC_S_CTRL, &ctrl); | ||
896 | |||
897 | if (atomic_read(&itv->capturing)) | ||
898 | ivtv_vapi(itv, CX2341X_ENC_MUTE_AUDIO, 1, 1); | ||
899 | |||
900 | IVTV_DEBUG_INFO("Mute\n"); | ||
901 | } | ||
902 | |||
903 | void ivtv_unmute(struct ivtv *itv) | ||
904 | { | ||
905 | struct v4l2_control ctrl = { V4L2_CID_AUDIO_MUTE, 0 }; | ||
906 | |||
907 | /* initialize or refresh input */ | ||
908 | if (atomic_read(&itv->capturing) == 0) | ||
909 | ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0); | ||
910 | |||
911 | ivtv_sleep_timeout(HZ / 10, 0); | ||
912 | |||
913 | if (atomic_read(&itv->capturing)) { | ||
914 | ivtv_vapi(itv, CX2341X_ENC_MISC, 1, 12); | ||
915 | ivtv_vapi(itv, CX2341X_ENC_MUTE_AUDIO, 1, 0); | ||
916 | } | ||
917 | |||
918 | /* Unmute */ | ||
919 | ivtv_control_ioctls(itv, VIDIOC_S_CTRL, &ctrl); | ||
920 | IVTV_DEBUG_INFO("Unmute\n"); | ||
921 | } | ||
diff --git a/drivers/media/video/ivtv/ivtv-fileops.h b/drivers/media/video/ivtv/ivtv-fileops.h new file mode 100644 index 000000000000..74a1745fabbc --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-fileops.h | |||
@@ -0,0 +1,44 @@ | |||
1 | /* | ||
2 | file operation functions | ||
3 | Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> | ||
4 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | /* Testing/Debugging */ | ||
22 | int ivtv_v4l2_open(struct inode *inode, struct file *filp); | ||
23 | ssize_t ivtv_v4l2_read(struct file *filp, char __user *buf, size_t count, | ||
24 | loff_t * pos); | ||
25 | ssize_t ivtv_v4l2_write(struct file *filp, const char __user *buf, size_t count, | ||
26 | loff_t * pos); | ||
27 | int ivtv_v4l2_close(struct inode *inode, struct file *filp); | ||
28 | unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table * wait); | ||
29 | unsigned int ivtv_v4l2_dec_poll(struct file *filp, poll_table * wait); | ||
30 | int ivtv_start_capture(struct ivtv_open_id *id); | ||
31 | void ivtv_stop_capture(struct ivtv_open_id *id, int gop_end); | ||
32 | int ivtv_start_decoding(struct ivtv_open_id *id, int speed); | ||
33 | void ivtv_mute(struct ivtv *itv); | ||
34 | void ivtv_unmute(struct ivtv *itv); | ||
35 | |||
36 | /* Utilities */ | ||
37 | |||
38 | /* Try to claim a stream for the filehandle. Return 0 on success, | ||
39 | -EBUSY if stream already claimed. Once a stream is claimed, it | ||
40 | remains claimed until the associated filehandle is closed. */ | ||
41 | int ivtv_claim_stream(struct ivtv_open_id *id, int type); | ||
42 | |||
43 | /* Release a previously claimed stream. */ | ||
44 | void ivtv_release_stream(struct ivtv_stream *s); | ||
diff --git a/drivers/media/video/ivtv/ivtv-firmware.c b/drivers/media/video/ivtv/ivtv-firmware.c new file mode 100644 index 000000000000..d4c910b782af --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-firmware.c | |||
@@ -0,0 +1,272 @@ | |||
1 | /* | ||
2 | ivtv firmware functions. | ||
3 | Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> | ||
4 | Copyright (C) 2004 Chris Kennedy <c@groovy.org> | ||
5 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2 of the License, or | ||
10 | (at your option) any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; if not, write to the Free Software | ||
19 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | */ | ||
21 | |||
22 | #include "ivtv-driver.h" | ||
23 | #include "ivtv-mailbox.h" | ||
24 | #include "ivtv-firmware.h" | ||
25 | #include <linux/firmware.h> | ||
26 | |||
27 | #define IVTV_MASK_SPU_ENABLE 0xFFFFFFFE | ||
28 | #define IVTV_MASK_VPU_ENABLE15 0xFFFFFFF6 | ||
29 | #define IVTV_MASK_VPU_ENABLE16 0xFFFFFFFB | ||
30 | #define IVTV_CMD_VDM_STOP 0x00000000 | ||
31 | #define IVTV_CMD_AO_STOP 0x00000005 | ||
32 | #define IVTV_CMD_APU_PING 0x00000000 | ||
33 | #define IVTV_CMD_VPU_STOP15 0xFFFFFFFE | ||
34 | #define IVTV_CMD_VPU_STOP16 0xFFFFFFEE | ||
35 | #define IVTV_CMD_HW_BLOCKS_RST 0xFFFFFFFF | ||
36 | #define IVTV_CMD_SPU_STOP 0x00000001 | ||
37 | #define IVTV_CMD_SDRAM_PRECHARGE_INIT 0x0000001A | ||
38 | #define IVTV_CMD_SDRAM_REFRESH_INIT 0x80000640 | ||
39 | #define IVTV_SDRAM_SLEEPTIME (60 * HZ / 100) /* 600 ms */ | ||
40 | |||
41 | #define IVTV_DECODE_INIT_MPEG_FILENAME "v4l-cx2341x-init.mpg" | ||
42 | #define IVTV_DECODE_INIT_MPEG_SIZE (152*1024) | ||
43 | |||
44 | /* Encoder/decoder firmware sizes */ | ||
45 | #define IVTV_FW_ENC_SIZE (376836) | ||
46 | #define IVTV_FW_DEC_SIZE (256*1024) | ||
47 | |||
48 | static int load_fw_direct(const char *fn, volatile u8 __iomem *mem, struct ivtv *itv, long size) | ||
49 | { | ||
50 | const struct firmware *fw = NULL; | ||
51 | int retries = 3; | ||
52 | |||
53 | retry: | ||
54 | if (retries && request_firmware(&fw, fn, &itv->dev->dev) == 0) { | ||
55 | int i; | ||
56 | volatile u32 __iomem *dst = (volatile u32 __iomem *)mem; | ||
57 | const u32 *src = (const u32 *)fw->data; | ||
58 | |||
59 | /* temporarily allow 256 KB encoding firmwares as well for | ||
60 | compatibility with blackbird cards */ | ||
61 | if (fw->size != size && fw->size != 256 * 1024) { | ||
62 | /* Due to race conditions in firmware loading (esp. with udev <0.95) | ||
63 | the wrong file was sometimes loaded. So we check filesizes to | ||
64 | see if at least the right-sized file was loaded. If not, then we | ||
65 | retry. */ | ||
66 | IVTV_INFO("retry: file loaded was not %s (expected size %ld, got %zd)\n", fn, size, fw->size); | ||
67 | release_firmware(fw); | ||
68 | retries--; | ||
69 | goto retry; | ||
70 | } | ||
71 | for (i = 0; i < fw->size; i += 4) { | ||
72 | /* no need for endianness conversion on the ppc */ | ||
73 | __raw_writel(*src, dst); | ||
74 | dst++; | ||
75 | src++; | ||
76 | } | ||
77 | release_firmware(fw); | ||
78 | IVTV_INFO("loaded %s firmware (%zd bytes)\n", fn, fw->size); | ||
79 | return size; | ||
80 | } | ||
81 | IVTV_ERR("unable to open firmware %s (must be %ld bytes)\n", fn, size); | ||
82 | IVTV_ERR("did you put the firmware in the hotplug firmware directory?\n"); | ||
83 | return -ENOMEM; | ||
84 | } | ||
85 | |||
86 | void ivtv_halt_firmware(struct ivtv *itv) | ||
87 | { | ||
88 | IVTV_DEBUG_INFO("Preparing for firmware halt.\n"); | ||
89 | if (itv->has_cx23415 && itv->dec_mbox.mbox) | ||
90 | ivtv_vapi(itv, CX2341X_DEC_HALT_FW, 0); | ||
91 | if (itv->enc_mbox.mbox) | ||
92 | ivtv_vapi(itv, CX2341X_ENC_HALT_FW, 0); | ||
93 | |||
94 | ivtv_sleep_timeout(HZ / 100, 0); | ||
95 | itv->enc_mbox.mbox = itv->dec_mbox.mbox = NULL; | ||
96 | |||
97 | IVTV_DEBUG_INFO("Stopping VDM\n"); | ||
98 | write_reg(IVTV_CMD_VDM_STOP, IVTV_REG_VDM); | ||
99 | |||
100 | IVTV_DEBUG_INFO("Stopping AO\n"); | ||
101 | write_reg(IVTV_CMD_AO_STOP, IVTV_REG_AO); | ||
102 | |||
103 | IVTV_DEBUG_INFO("pinging (?) APU\n"); | ||
104 | write_reg(IVTV_CMD_APU_PING, IVTV_REG_APU); | ||
105 | |||
106 | IVTV_DEBUG_INFO("Stopping VPU\n"); | ||
107 | if (!itv->has_cx23415) | ||
108 | write_reg(IVTV_CMD_VPU_STOP16, IVTV_REG_VPU); | ||
109 | else | ||
110 | write_reg(IVTV_CMD_VPU_STOP15, IVTV_REG_VPU); | ||
111 | |||
112 | IVTV_DEBUG_INFO("Resetting Hw Blocks\n"); | ||
113 | write_reg(IVTV_CMD_HW_BLOCKS_RST, IVTV_REG_HW_BLOCKS); | ||
114 | |||
115 | IVTV_DEBUG_INFO("Stopping SPU\n"); | ||
116 | write_reg(IVTV_CMD_SPU_STOP, IVTV_REG_SPU); | ||
117 | |||
118 | ivtv_sleep_timeout(HZ / 100, 0); | ||
119 | |||
120 | IVTV_DEBUG_INFO("init Encoder SDRAM pre-charge\n"); | ||
121 | write_reg(IVTV_CMD_SDRAM_PRECHARGE_INIT, IVTV_REG_ENC_SDRAM_PRECHARGE); | ||
122 | |||
123 | IVTV_DEBUG_INFO("init Encoder SDRAM refresh to 1us\n"); | ||
124 | write_reg(IVTV_CMD_SDRAM_REFRESH_INIT, IVTV_REG_ENC_SDRAM_REFRESH); | ||
125 | |||
126 | if (itv->has_cx23415) { | ||
127 | IVTV_DEBUG_INFO("init Decoder SDRAM pre-charge\n"); | ||
128 | write_reg(IVTV_CMD_SDRAM_PRECHARGE_INIT, IVTV_REG_DEC_SDRAM_PRECHARGE); | ||
129 | |||
130 | IVTV_DEBUG_INFO("init Decoder SDRAM refresh to 1us\n"); | ||
131 | write_reg(IVTV_CMD_SDRAM_REFRESH_INIT, IVTV_REG_DEC_SDRAM_REFRESH); | ||
132 | } | ||
133 | |||
134 | IVTV_DEBUG_INFO("Sleeping for %dms (600 recommended)\n", | ||
135 | (int)(IVTV_SDRAM_SLEEPTIME * 1000 / HZ)); | ||
136 | ivtv_sleep_timeout(IVTV_SDRAM_SLEEPTIME, 0); | ||
137 | } | ||
138 | |||
139 | void ivtv_firmware_versions(struct ivtv *itv) | ||
140 | { | ||
141 | u32 data[CX2341X_MBOX_MAX_DATA]; | ||
142 | |||
143 | /* Encoder */ | ||
144 | ivtv_vapi_result(itv, data, CX2341X_ENC_GET_VERSION, 0); | ||
145 | IVTV_INFO("Encoder revision: 0x%08x\n", data[0]); | ||
146 | |||
147 | if (data[0] != 0x02060039) | ||
148 | IVTV_WARN("Recommended firmware version is 0x02060039.\n"); | ||
149 | |||
150 | if (itv->has_cx23415) { | ||
151 | /* Decoder */ | ||
152 | ivtv_vapi_result(itv, data, CX2341X_DEC_GET_VERSION, 0); | ||
153 | IVTV_INFO("Decoder revision: 0x%08x\n", data[0]); | ||
154 | } | ||
155 | } | ||
156 | |||
157 | static int ivtv_firmware_copy(struct ivtv *itv) | ||
158 | { | ||
159 | IVTV_DEBUG_INFO("Loading encoder image\n"); | ||
160 | if (load_fw_direct(CX2341X_FIRM_ENC_FILENAME, | ||
161 | itv->enc_mem, itv, IVTV_FW_ENC_SIZE) != IVTV_FW_ENC_SIZE) { | ||
162 | IVTV_DEBUG_WARN("failed loading encoder firmware\n"); | ||
163 | return -3; | ||
164 | } | ||
165 | if (!itv->has_cx23415) | ||
166 | return 0; | ||
167 | |||
168 | IVTV_DEBUG_INFO("Loading decoder image\n"); | ||
169 | if (load_fw_direct(CX2341X_FIRM_DEC_FILENAME, | ||
170 | itv->dec_mem, itv, IVTV_FW_DEC_SIZE) != IVTV_FW_DEC_SIZE) { | ||
171 | IVTV_DEBUG_WARN("failed loading decoder firmware\n"); | ||
172 | return -1; | ||
173 | } | ||
174 | return 0; | ||
175 | } | ||
176 | |||
177 | static volatile struct ivtv_mailbox __iomem *ivtv_search_mailbox(const volatile u8 __iomem *mem, u32 size) | ||
178 | { | ||
179 | int i; | ||
180 | |||
181 | /* mailbox is preceeded by a 16 byte 'magic cookie' starting at a 256-byte | ||
182 | address boundary */ | ||
183 | for (i = 0; i < size; i += 0x100) { | ||
184 | if (readl(mem + i) == 0x12345678 && | ||
185 | readl(mem + i + 4) == 0x34567812 && | ||
186 | readl(mem + i + 8) == 0x56781234 && | ||
187 | readl(mem + i + 12) == 0x78123456) { | ||
188 | return (volatile struct ivtv_mailbox __iomem *)(mem + i + 16); | ||
189 | } | ||
190 | } | ||
191 | return NULL; | ||
192 | } | ||
193 | |||
194 | int ivtv_firmware_init(struct ivtv *itv) | ||
195 | { | ||
196 | int err; | ||
197 | |||
198 | ivtv_halt_firmware(itv); | ||
199 | |||
200 | /* load firmware */ | ||
201 | err = ivtv_firmware_copy(itv); | ||
202 | if (err) { | ||
203 | IVTV_DEBUG_WARN("Error %d loading firmware\n", err); | ||
204 | return err; | ||
205 | } | ||
206 | |||
207 | /* start firmware */ | ||
208 | write_reg(read_reg(IVTV_REG_SPU) & IVTV_MASK_SPU_ENABLE, IVTV_REG_SPU); | ||
209 | ivtv_sleep_timeout(HZ / 10, 0); | ||
210 | if (itv->has_cx23415) | ||
211 | write_reg(read_reg(IVTV_REG_VPU) & IVTV_MASK_VPU_ENABLE15, IVTV_REG_VPU); | ||
212 | else | ||
213 | write_reg(read_reg(IVTV_REG_VPU) & IVTV_MASK_VPU_ENABLE16, IVTV_REG_VPU); | ||
214 | ivtv_sleep_timeout(HZ / 10, 0); | ||
215 | |||
216 | /* find mailboxes and ping firmware */ | ||
217 | itv->enc_mbox.mbox = ivtv_search_mailbox(itv->enc_mem, IVTV_ENCODER_SIZE); | ||
218 | if (itv->enc_mbox.mbox == NULL) | ||
219 | IVTV_ERR("Encoder mailbox not found\n"); | ||
220 | else if (ivtv_vapi(itv, CX2341X_ENC_PING_FW, 0)) { | ||
221 | IVTV_ERR("Encoder firmware dead!\n"); | ||
222 | itv->enc_mbox.mbox = NULL; | ||
223 | } | ||
224 | if (itv->enc_mbox.mbox == NULL) | ||
225 | return -ENODEV; | ||
226 | |||
227 | if (!itv->has_cx23415) | ||
228 | return 0; | ||
229 | |||
230 | itv->dec_mbox.mbox = ivtv_search_mailbox(itv->dec_mem, IVTV_DECODER_SIZE); | ||
231 | if (itv->dec_mbox.mbox == NULL) | ||
232 | IVTV_ERR("Decoder mailbox not found\n"); | ||
233 | else if (itv->has_cx23415 && ivtv_vapi(itv, CX2341X_DEC_PING_FW, 0)) { | ||
234 | IVTV_ERR("Decoder firmware dead!\n"); | ||
235 | itv->dec_mbox.mbox = NULL; | ||
236 | } | ||
237 | return itv->dec_mbox.mbox ? 0 : -ENODEV; | ||
238 | } | ||
239 | |||
240 | void ivtv_init_mpeg_decoder(struct ivtv *itv) | ||
241 | { | ||
242 | u32 data[CX2341X_MBOX_MAX_DATA]; | ||
243 | long readbytes; | ||
244 | volatile u8 __iomem *mem_offset; | ||
245 | |||
246 | data[0] = 0; | ||
247 | data[1] = itv->params.width; /* YUV source width */ | ||
248 | data[2] = itv->params.height; | ||
249 | data[3] = itv->params.audio_properties; /* Audio settings to use, | ||
250 | bitmap. see docs. */ | ||
251 | if (ivtv_api(itv, CX2341X_DEC_SET_DECODER_SOURCE, 4, data)) { | ||
252 | IVTV_ERR("ivtv_init_mpeg_decoder failed to set decoder source\n"); | ||
253 | return; | ||
254 | } | ||
255 | |||
256 | if (ivtv_vapi(itv, CX2341X_DEC_START_PLAYBACK, 2, 0, 1) != 0) { | ||
257 | IVTV_ERR("ivtv_init_mpeg_decoder failed to start playback\n"); | ||
258 | return; | ||
259 | } | ||
260 | ivtv_api_get_data(&itv->dec_mbox, IVTV_MBOX_DMA, data); | ||
261 | mem_offset = itv->dec_mem + data[1]; | ||
262 | |||
263 | if ((readbytes = load_fw_direct(IVTV_DECODE_INIT_MPEG_FILENAME, | ||
264 | mem_offset, itv, IVTV_DECODE_INIT_MPEG_SIZE)) <= 0) { | ||
265 | IVTV_DEBUG_WARN("failed to read mpeg decoder initialisation file %s\n", | ||
266 | IVTV_DECODE_INIT_MPEG_FILENAME); | ||
267 | } else { | ||
268 | ivtv_vapi(itv, CX2341X_DEC_SCHED_DMA_FROM_HOST, 3, 0, readbytes, 0); | ||
269 | ivtv_sleep_timeout(HZ / 10, 0); | ||
270 | } | ||
271 | ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 4, 0, 0, 0, 1); | ||
272 | } | ||
diff --git a/drivers/media/video/ivtv/ivtv-firmware.h b/drivers/media/video/ivtv/ivtv-firmware.h new file mode 100644 index 000000000000..8b2ffe658905 --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-firmware.h | |||
@@ -0,0 +1,25 @@ | |||
1 | /* | ||
2 | ivtv firmware functions. | ||
3 | Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> | ||
4 | Copyright (C) 2004 Chris Kennedy <c@groovy.org> | ||
5 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2 of the License, or | ||
10 | (at your option) any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; if not, write to the Free Software | ||
19 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | */ | ||
21 | |||
22 | int ivtv_firmware_init(struct ivtv *itv); | ||
23 | void ivtv_firmware_versions(struct ivtv *itv); | ||
24 | void ivtv_halt_firmware(struct ivtv *itv); | ||
25 | void ivtv_init_mpeg_decoder(struct ivtv *itv); | ||
diff --git a/drivers/media/video/ivtv/ivtv-gpio.c b/drivers/media/video/ivtv/ivtv-gpio.c new file mode 100644 index 000000000000..bc8f8ca2961f --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-gpio.c | |||
@@ -0,0 +1,307 @@ | |||
1 | /* | ||
2 | gpio functions. | ||
3 | Merging GPIO support into driver: | ||
4 | Copyright (C) 2004 Chris Kennedy <c@groovy.org> | ||
5 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2 of the License, or | ||
10 | (at your option) any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; if not, write to the Free Software | ||
19 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | */ | ||
21 | |||
22 | #include "ivtv-driver.h" | ||
23 | #include "ivtv-cards.h" | ||
24 | #include "ivtv-gpio.h" | ||
25 | #include <media/tuner.h> | ||
26 | |||
27 | /* | ||
28 | * GPIO assignment of Yuan MPG600/MPG160 | ||
29 | * | ||
30 | * bit 15 14 13 12 | 11 10 9 8 | 7 6 5 4 | 3 2 1 0 | ||
31 | * OUTPUT IN1 IN0 AM3 AM2 AM1 AM0 | ||
32 | * INPUT DM1 DM0 | ||
33 | * | ||
34 | * IN* : Input selection | ||
35 | * IN1 IN0 | ||
36 | * 1 1 N/A | ||
37 | * 1 0 Line | ||
38 | * 0 1 N/A | ||
39 | * 0 0 Tuner | ||
40 | * | ||
41 | * AM* : Audio Mode | ||
42 | * AM3 0: Normal 1: Mixed(Sub+Main channel) | ||
43 | * AM2 0: Subchannel 1: Main channel | ||
44 | * AM1 0: Stereo 1: Mono | ||
45 | * AM0 0: Normal 1: Mute | ||
46 | * | ||
47 | * DM* : Detected tuner audio Mode | ||
48 | * DM1 0: Stereo 1: Mono | ||
49 | * DM0 0: Multiplex 1: Normal | ||
50 | * | ||
51 | * GPIO Initial Settings | ||
52 | * MPG600 MPG160 | ||
53 | * DIR 0x3080 0x7080 | ||
54 | * OUTPUT 0x000C 0x400C | ||
55 | * | ||
56 | * Special thanks to Makoto Iguchi <iguchi@tahoo.org> and Mr. Anonymous | ||
57 | * for analyzing GPIO of MPG160. | ||
58 | * | ||
59 | ***************************************************************************** | ||
60 | * | ||
61 | * GPIO assignment of Avermedia M179 (per information direct from AVerMedia) | ||
62 | * | ||
63 | * bit 15 14 13 12 | 11 10 9 8 | 7 6 5 4 | 3 2 1 0 | ||
64 | * OUTPUT IN0 AM0 IN1 AM1 AM2 IN2 BR0 BR1 | ||
65 | * INPUT | ||
66 | * | ||
67 | * IN* : Input selection | ||
68 | * IN0 IN1 IN2 | ||
69 | * * 1 * Mute | ||
70 | * 0 0 0 Line-In | ||
71 | * 1 0 0 TV Tuner Audio | ||
72 | * 0 0 1 FM Audio | ||
73 | * 1 0 1 Mute | ||
74 | * | ||
75 | * AM* : Audio Mode | ||
76 | * AM0 AM1 AM2 | ||
77 | * 0 0 0 TV Tuner Audio: L_OUT=(L+R)/2, R_OUT=SAP | ||
78 | * 0 0 1 TV Tuner Audio: L_OUT=R_OUT=SAP (SAP) | ||
79 | * 0 1 0 TV Tuner Audio: L_OUT=L, R_OUT=R (stereo) | ||
80 | * 0 1 1 TV Tuner Audio: mute | ||
81 | * 1 * * TV Tuner Audio: L_OUT=R_OUT=(L+R)/2 (mono) | ||
82 | * | ||
83 | * BR* : Audio Sample Rate (BR stands for bitrate for some reason) | ||
84 | * BR0 BR1 | ||
85 | * 0 0 32 kHz | ||
86 | * 0 1 44.1 kHz | ||
87 | * 1 0 48 kHz | ||
88 | * | ||
89 | * DM* : Detected tuner audio Mode | ||
90 | * Unknown currently | ||
91 | * | ||
92 | * Special thanks to AVerMedia Technologies, Inc. and Jiun-Kuei Jung at | ||
93 | * AVerMedia for providing the GPIO information used to add support | ||
94 | * for the M179 cards. | ||
95 | */ | ||
96 | |||
97 | /********************* GPIO stuffs *********************/ | ||
98 | |||
99 | /* GPIO registers */ | ||
100 | #define IVTV_REG_GPIO_IN 0x9008 | ||
101 | #define IVTV_REG_GPIO_OUT 0x900c | ||
102 | #define IVTV_REG_GPIO_DIR 0x9020 | ||
103 | |||
104 | void ivtv_reset_ir_gpio(struct ivtv *itv) | ||
105 | { | ||
106 | int curdir, curout; | ||
107 | |||
108 | if (itv->card->type != IVTV_CARD_PVR_150) | ||
109 | return; | ||
110 | IVTV_DEBUG_INFO("Resetting PVR150 IR\n"); | ||
111 | curout = read_reg(IVTV_REG_GPIO_OUT); | ||
112 | curdir = read_reg(IVTV_REG_GPIO_DIR); | ||
113 | curdir |= 0x80; | ||
114 | write_reg(curdir, IVTV_REG_GPIO_DIR); | ||
115 | curout = (curout & ~0xF) | 1; | ||
116 | write_reg(curout, IVTV_REG_GPIO_OUT); | ||
117 | /* We could use something else for smaller time */ | ||
118 | current->state = TASK_INTERRUPTIBLE; | ||
119 | schedule_timeout(1); | ||
120 | curout |= 2; | ||
121 | write_reg(curout, IVTV_REG_GPIO_OUT); | ||
122 | curdir &= ~0x80; | ||
123 | write_reg(curdir, IVTV_REG_GPIO_DIR); | ||
124 | } | ||
125 | |||
126 | #ifdef HAVE_XC3028 | ||
127 | int ivtv_reset_tuner_gpio(enum v4l2_tuner_type mode, void *priv, int ptr) | ||
128 | { | ||
129 | int curdir, curout; | ||
130 | struct ivtv *itv = (struct ivtv *) priv; | ||
131 | |||
132 | if (itv->card->type != IVTV_CARD_PG600V2 || itv->options.tuner != TUNER_XCEIVE_XC3028) | ||
133 | return -EINVAL; | ||
134 | IVTV_INFO("Resetting tuner.\n"); | ||
135 | curout = read_reg(IVTV_REG_GPIO_OUT); | ||
136 | curdir = read_reg(IVTV_REG_GPIO_DIR); | ||
137 | curdir |= (1 << 12); /* GPIO bit 12 */ | ||
138 | |||
139 | curout &= ~(1 << 12); | ||
140 | write_reg(curout, IVTV_REG_GPIO_OUT); | ||
141 | current->state = TASK_INTERRUPTIBLE; | ||
142 | schedule_timeout(1); | ||
143 | |||
144 | curout |= (1 << 12); | ||
145 | write_reg(curout, IVTV_REG_GPIO_OUT); | ||
146 | current->state = TASK_INTERRUPTIBLE; | ||
147 | schedule_timeout(1); | ||
148 | |||
149 | return 0; | ||
150 | } | ||
151 | #endif | ||
152 | |||
153 | void ivtv_gpio_init(struct ivtv *itv) | ||
154 | { | ||
155 | if (itv->card->gpio_init.direction == 0) | ||
156 | return; | ||
157 | |||
158 | IVTV_DEBUG_INFO("GPIO initial dir: %08x out: %08x\n", | ||
159 | read_reg(IVTV_REG_GPIO_DIR), read_reg(IVTV_REG_GPIO_OUT)); | ||
160 | |||
161 | /* init output data then direction */ | ||
162 | write_reg(itv->card->gpio_init.initial_value, IVTV_REG_GPIO_OUT); | ||
163 | write_reg(itv->card->gpio_init.direction, IVTV_REG_GPIO_DIR); | ||
164 | } | ||
165 | |||
166 | static struct v4l2_queryctrl gpio_ctrl_mute = { | ||
167 | .id = V4L2_CID_AUDIO_MUTE, | ||
168 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
169 | .name = "Mute", | ||
170 | .minimum = 0, | ||
171 | .maximum = 1, | ||
172 | .step = 1, | ||
173 | .default_value = 1, | ||
174 | .flags = 0, | ||
175 | }; | ||
176 | |||
177 | int ivtv_gpio(struct ivtv *itv, unsigned int command, void *arg) | ||
178 | { | ||
179 | struct v4l2_tuner *tuner = arg; | ||
180 | struct v4l2_control *ctrl = arg; | ||
181 | struct v4l2_routing *route = arg; | ||
182 | u16 mask, data; | ||
183 | |||
184 | switch (command) { | ||
185 | case VIDIOC_INT_AUDIO_CLOCK_FREQ: | ||
186 | mask = itv->card->gpio_audio_freq.mask; | ||
187 | switch (*(u32 *)arg) { | ||
188 | case 32000: | ||
189 | data = itv->card->gpio_audio_freq.f32000; | ||
190 | break; | ||
191 | case 44100: | ||
192 | data = itv->card->gpio_audio_freq.f44100; | ||
193 | break; | ||
194 | case 48000: | ||
195 | default: | ||
196 | data = itv->card->gpio_audio_freq.f48000; | ||
197 | break; | ||
198 | } | ||
199 | break; | ||
200 | |||
201 | case VIDIOC_G_TUNER: | ||
202 | mask = itv->card->gpio_audio_detect.mask; | ||
203 | if (mask == 0 || (read_reg(IVTV_REG_GPIO_IN) & mask)) | ||
204 | tuner->rxsubchans = V4L2_TUNER_MODE_STEREO | | ||
205 | V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; | ||
206 | else | ||
207 | tuner->rxsubchans = V4L2_TUNER_SUB_MONO; | ||
208 | return 0; | ||
209 | |||
210 | case VIDIOC_S_TUNER: | ||
211 | mask = itv->card->gpio_audio_mode.mask; | ||
212 | switch (tuner->audmode) { | ||
213 | case V4L2_TUNER_MODE_LANG1: | ||
214 | data = itv->card->gpio_audio_mode.lang1; | ||
215 | break; | ||
216 | case V4L2_TUNER_MODE_LANG2: | ||
217 | data = itv->card->gpio_audio_mode.lang2; | ||
218 | break; | ||
219 | case V4L2_TUNER_MODE_MONO: | ||
220 | data = itv->card->gpio_audio_mode.mono; | ||
221 | break; | ||
222 | case V4L2_TUNER_MODE_STEREO: | ||
223 | case V4L2_TUNER_MODE_LANG1_LANG2: | ||
224 | default: | ||
225 | data = itv->card->gpio_audio_mode.stereo; | ||
226 | break; | ||
227 | } | ||
228 | break; | ||
229 | |||
230 | case AUDC_SET_RADIO: | ||
231 | mask = itv->card->gpio_audio_input.mask; | ||
232 | data = itv->card->gpio_audio_input.radio; | ||
233 | break; | ||
234 | |||
235 | case VIDIOC_S_STD: | ||
236 | mask = itv->card->gpio_audio_input.mask; | ||
237 | data = itv->card->gpio_audio_input.tuner; | ||
238 | break; | ||
239 | |||
240 | case VIDIOC_INT_S_AUDIO_ROUTING: | ||
241 | if (route->input > 2) | ||
242 | return -EINVAL; | ||
243 | mask = itv->card->gpio_audio_input.mask; | ||
244 | switch (route->input) { | ||
245 | case 0: | ||
246 | data = itv->card->gpio_audio_input.tuner; | ||
247 | break; | ||
248 | case 1: | ||
249 | data = itv->card->gpio_audio_input.linein; | ||
250 | break; | ||
251 | case 2: | ||
252 | default: | ||
253 | data = itv->card->gpio_audio_input.radio; | ||
254 | break; | ||
255 | } | ||
256 | break; | ||
257 | |||
258 | case VIDIOC_G_CTRL: | ||
259 | if (ctrl->id != V4L2_CID_AUDIO_MUTE) | ||
260 | return -EINVAL; | ||
261 | mask = itv->card->gpio_audio_mute.mask; | ||
262 | data = itv->card->gpio_audio_mute.mute; | ||
263 | ctrl->value = (read_reg(IVTV_REG_GPIO_OUT) & mask) == data; | ||
264 | return 0; | ||
265 | |||
266 | case VIDIOC_S_CTRL: | ||
267 | if (ctrl->id != V4L2_CID_AUDIO_MUTE) | ||
268 | return -EINVAL; | ||
269 | mask = itv->card->gpio_audio_mute.mask; | ||
270 | data = ctrl->value ? itv->card->gpio_audio_mute.mute : 0; | ||
271 | break; | ||
272 | |||
273 | case VIDIOC_QUERYCTRL: | ||
274 | { | ||
275 | struct v4l2_queryctrl *qc = arg; | ||
276 | |||
277 | if (qc->id != V4L2_CID_AUDIO_MUTE) | ||
278 | return -EINVAL; | ||
279 | *qc = gpio_ctrl_mute; | ||
280 | return 0; | ||
281 | } | ||
282 | |||
283 | case VIDIOC_LOG_STATUS: | ||
284 | IVTV_INFO("GPIO status: DIR=0x%04x OUT=0x%04x IN=0x%04x\n", | ||
285 | read_reg(IVTV_REG_GPIO_DIR), read_reg(IVTV_REG_GPIO_OUT), | ||
286 | read_reg(IVTV_REG_GPIO_IN)); | ||
287 | return 0; | ||
288 | |||
289 | case VIDIOC_INT_S_VIDEO_ROUTING: | ||
290 | if (route->input > 2) /* 0:Tuner 1:Composite 2:S-Video */ | ||
291 | return -EINVAL; | ||
292 | mask = itv->card->gpio_video_input.mask; | ||
293 | if (route->input == 0) | ||
294 | data = itv->card->gpio_video_input.tuner; | ||
295 | else if (route->input == 1) | ||
296 | data = itv->card->gpio_video_input.composite; | ||
297 | else | ||
298 | data = itv->card->gpio_video_input.svideo; | ||
299 | break; | ||
300 | |||
301 | default: | ||
302 | return -EINVAL; | ||
303 | } | ||
304 | if (mask) | ||
305 | write_reg((read_reg(IVTV_REG_GPIO_OUT) & ~mask) | (data & mask), IVTV_REG_GPIO_OUT); | ||
306 | return 0; | ||
307 | } | ||
diff --git a/drivers/media/video/ivtv/ivtv-gpio.h b/drivers/media/video/ivtv/ivtv-gpio.h new file mode 100644 index 000000000000..c301d2a39346 --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-gpio.h | |||
@@ -0,0 +1,25 @@ | |||
1 | /* | ||
2 | gpio functions. | ||
3 | Copyright (C) 2004 Chris Kennedy <c@groovy.org> | ||
4 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | /* GPIO stuff */ | ||
22 | void ivtv_gpio_init(struct ivtv *itv); | ||
23 | void ivtv_reset_ir_gpio(struct ivtv *itv); | ||
24 | int ivtv_reset_tuner_gpio(enum v4l2_tuner_type mode, void *priv, int ptr); | ||
25 | int ivtv_gpio(struct ivtv *itv, unsigned int command, void *arg); | ||
diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c new file mode 100644 index 000000000000..50624c6a62a5 --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-i2c.c | |||
@@ -0,0 +1,748 @@ | |||
1 | /* | ||
2 | I2C functions | ||
3 | Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> | ||
4 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | /* | ||
22 | This file includes an i2c implementation that was reverse engineered | ||
23 | from the Hauppauge windows driver. Older ivtv versions used i2c-algo-bit, | ||
24 | which whilst fine under most circumstances, had trouble with the Zilog | ||
25 | CPU on the PVR-150 which handles IR functions (occasional inability to | ||
26 | communicate with the chip until it was reset) and also with the i2c | ||
27 | bus being completely unreachable when multiple PVR cards were present. | ||
28 | |||
29 | The implementation is very similar to i2c-algo-bit, but there are enough | ||
30 | subtle differences that the two are hard to merge. The general strategy | ||
31 | employed by i2c-algo-bit is to use udelay() to implement the timing | ||
32 | when putting out bits on the scl/sda lines. The general strategy taken | ||
33 | here is to poll the lines for state changes (see ivtv_waitscl and | ||
34 | ivtv_waitsda). In addition there are small delays at various locations | ||
35 | which poll the SCL line 5 times (ivtv_scldelay). I would guess that | ||
36 | since this is memory mapped I/O that the length of those delays is tied | ||
37 | to the PCI bus clock. There is some extra code to do with recovery | ||
38 | and retries. Since it is not known what causes the actual i2c problems | ||
39 | in the first place, the only goal if one was to attempt to use | ||
40 | i2c-algo-bit would be to try to make it follow the same code path. | ||
41 | This would be a lot of work, and I'm also not convinced that it would | ||
42 | provide a generic benefit to i2c-algo-bit. Therefore consider this | ||
43 | an engineering solution -- not pretty, but it works. | ||
44 | |||
45 | Some more general comments about what we are doing: | ||
46 | |||
47 | The i2c bus is a 2 wire serial bus, with clock (SCL) and data (SDA) | ||
48 | lines. To communicate on the bus (as a master, we don't act as a slave), | ||
49 | we first initiate a start condition (ivtv_start). We then write the | ||
50 | address of the device that we want to communicate with, along with a flag | ||
51 | that indicates whether this is a read or a write. The slave then issues | ||
52 | an ACK signal (ivtv_ack), which tells us that it is ready for reading / | ||
53 | writing. We then proceed with reading or writing (ivtv_read/ivtv_write), | ||
54 | and finally issue a stop condition (ivtv_stop) to make the bus available | ||
55 | to other masters. | ||
56 | |||
57 | There is an additional form of transaction where a write may be | ||
58 | immediately followed by a read. In this case, there is no intervening | ||
59 | stop condition. (Only the msp3400 chip uses this method of data transfer). | ||
60 | */ | ||
61 | |||
62 | #include "ivtv-driver.h" | ||
63 | #include "ivtv-cards.h" | ||
64 | #include "ivtv-gpio.h" | ||
65 | #include "ivtv-i2c.h" | ||
66 | |||
67 | #include <media/ir-kbd-i2c.h> | ||
68 | |||
69 | /* i2c implementation for cx23415/6 chip, ivtv project. | ||
70 | * Author: Kevin Thayer (nufan_wfk at yahoo.com) | ||
71 | */ | ||
72 | /* i2c stuff */ | ||
73 | #define IVTV_REG_I2C_SETSCL_OFFSET 0x7000 | ||
74 | #define IVTV_REG_I2C_SETSDA_OFFSET 0x7004 | ||
75 | #define IVTV_REG_I2C_GETSCL_OFFSET 0x7008 | ||
76 | #define IVTV_REG_I2C_GETSDA_OFFSET 0x700c | ||
77 | |||
78 | #ifndef I2C_ADAP_CLASS_TV_ANALOG | ||
79 | #define I2C_ADAP_CLASS_TV_ANALOG I2C_CLASS_TV_ANALOG | ||
80 | #endif /* I2C_ADAP_CLASS_TV_ANALOG */ | ||
81 | |||
82 | #define IVTV_CS53L32A_I2C_ADDR 0x11 | ||
83 | #define IVTV_CX25840_I2C_ADDR 0x44 | ||
84 | #define IVTV_SAA7115_I2C_ADDR 0x21 | ||
85 | #define IVTV_SAA7127_I2C_ADDR 0x44 | ||
86 | #define IVTV_SAA717x_I2C_ADDR 0x21 | ||
87 | #define IVTV_MSP3400_I2C_ADDR 0x40 | ||
88 | #define IVTV_HAUPPAUGE_I2C_ADDR 0x50 | ||
89 | #define IVTV_WM8739_I2C_ADDR 0x1a | ||
90 | #define IVTV_WM8775_I2C_ADDR 0x1b | ||
91 | #define IVTV_TEA5767_I2C_ADDR 0x60 | ||
92 | #define IVTV_UPD64031A_I2C_ADDR 0x12 | ||
93 | #define IVTV_UPD64083_I2C_ADDR 0x5c | ||
94 | #define IVTV_TDA985X_I2C_ADDR 0x5b | ||
95 | |||
96 | /* This array should match the IVTV_HW_ defines */ | ||
97 | static const u8 hw_driverids[] = { | ||
98 | I2C_DRIVERID_CX25840, | ||
99 | I2C_DRIVERID_SAA711X, | ||
100 | I2C_DRIVERID_SAA7127, | ||
101 | I2C_DRIVERID_MSP3400, | ||
102 | I2C_DRIVERID_TUNER, | ||
103 | I2C_DRIVERID_WM8775, | ||
104 | I2C_DRIVERID_CS53L32A, | ||
105 | I2C_DRIVERID_TVEEPROM, | ||
106 | I2C_DRIVERID_SAA711X, | ||
107 | I2C_DRIVERID_TVAUDIO, | ||
108 | I2C_DRIVERID_UPD64031A, | ||
109 | I2C_DRIVERID_UPD64083, | ||
110 | I2C_DRIVERID_SAA717X, | ||
111 | I2C_DRIVERID_WM8739, | ||
112 | 0 /* IVTV_HW_GPIO dummy driver ID */ | ||
113 | }; | ||
114 | |||
115 | /* This array should match the IVTV_HW_ defines */ | ||
116 | static const char * const hw_drivernames[] = { | ||
117 | "cx2584x", | ||
118 | "saa7115", | ||
119 | "saa7127", | ||
120 | "msp3400", | ||
121 | "tuner", | ||
122 | "wm8775", | ||
123 | "cs53l32a", | ||
124 | "tveeprom", | ||
125 | "saa7114", | ||
126 | "tvaudio", | ||
127 | "upd64031a", | ||
128 | "upd64083", | ||
129 | "saa717x", | ||
130 | "wm8739", | ||
131 | "gpio", | ||
132 | }; | ||
133 | |||
134 | static int attach_inform(struct i2c_client *client) | ||
135 | { | ||
136 | struct ivtv *itv = (struct ivtv *)i2c_get_adapdata(client->adapter); | ||
137 | int i; | ||
138 | |||
139 | IVTV_DEBUG_I2C("i2c client attach\n"); | ||
140 | for (i = 0; i < I2C_CLIENTS_MAX; i++) { | ||
141 | if (itv->i2c_clients[i] == NULL) { | ||
142 | itv->i2c_clients[i] = client; | ||
143 | break; | ||
144 | } | ||
145 | } | ||
146 | if (i == I2C_CLIENTS_MAX) { | ||
147 | IVTV_ERR("insufficient room for new I2C client!\n"); | ||
148 | } | ||
149 | return 0; | ||
150 | } | ||
151 | |||
152 | static int detach_inform(struct i2c_client *client) | ||
153 | { | ||
154 | int i; | ||
155 | struct ivtv *itv = (struct ivtv *)i2c_get_adapdata(client->adapter); | ||
156 | |||
157 | IVTV_DEBUG_I2C("i2c client detach\n"); | ||
158 | for (i = 0; i < I2C_CLIENTS_MAX; i++) { | ||
159 | if (itv->i2c_clients[i] == client) { | ||
160 | itv->i2c_clients[i] = NULL; | ||
161 | break; | ||
162 | } | ||
163 | } | ||
164 | IVTV_DEBUG_I2C("i2c detach [client=%s,%s]\n", | ||
165 | client->name, (i < I2C_CLIENTS_MAX) ? "ok" : "failed"); | ||
166 | |||
167 | return 0; | ||
168 | } | ||
169 | |||
170 | /* Set the serial clock line to the desired state */ | ||
171 | static void ivtv_setscl(struct ivtv *itv, int state) | ||
172 | { | ||
173 | /* write them out */ | ||
174 | /* write bits are inverted */ | ||
175 | write_reg(~state, IVTV_REG_I2C_SETSCL_OFFSET); | ||
176 | } | ||
177 | |||
178 | /* Set the serial data line to the desired state */ | ||
179 | static void ivtv_setsda(struct ivtv *itv, int state) | ||
180 | { | ||
181 | /* write them out */ | ||
182 | /* write bits are inverted */ | ||
183 | write_reg(~state & 1, IVTV_REG_I2C_SETSDA_OFFSET); | ||
184 | } | ||
185 | |||
186 | /* Read the serial clock line */ | ||
187 | static int ivtv_getscl(struct ivtv *itv) | ||
188 | { | ||
189 | return read_reg(IVTV_REG_I2C_GETSCL_OFFSET) & 1; | ||
190 | } | ||
191 | |||
192 | /* Read the serial data line */ | ||
193 | static int ivtv_getsda(struct ivtv *itv) | ||
194 | { | ||
195 | return read_reg(IVTV_REG_I2C_GETSDA_OFFSET) & 1; | ||
196 | } | ||
197 | |||
198 | /* Implement a short delay by polling the serial clock line */ | ||
199 | static void ivtv_scldelay(struct ivtv *itv) | ||
200 | { | ||
201 | int i; | ||
202 | |||
203 | for (i = 0; i < 5; ++i) | ||
204 | ivtv_getscl(itv); | ||
205 | } | ||
206 | |||
207 | /* Wait for the serial clock line to become set to a specific value */ | ||
208 | static int ivtv_waitscl(struct ivtv *itv, int val) | ||
209 | { | ||
210 | int i; | ||
211 | |||
212 | ivtv_scldelay(itv); | ||
213 | for (i = 0; i < 1000; ++i) { | ||
214 | if (ivtv_getscl(itv) == val) | ||
215 | return 1; | ||
216 | } | ||
217 | return 0; | ||
218 | } | ||
219 | |||
220 | /* Wait for the serial data line to become set to a specific value */ | ||
221 | static int ivtv_waitsda(struct ivtv *itv, int val) | ||
222 | { | ||
223 | int i; | ||
224 | |||
225 | ivtv_scldelay(itv); | ||
226 | for (i = 0; i < 1000; ++i) { | ||
227 | if (ivtv_getsda(itv) == val) | ||
228 | return 1; | ||
229 | } | ||
230 | return 0; | ||
231 | } | ||
232 | |||
233 | /* Wait for the slave to issue an ACK */ | ||
234 | static int ivtv_ack(struct ivtv *itv) | ||
235 | { | ||
236 | int ret = 0; | ||
237 | |||
238 | if (ivtv_getscl(itv) == 1) { | ||
239 | IVTV_DEBUG_I2C("SCL was high starting an ack\n"); | ||
240 | ivtv_setscl(itv, 0); | ||
241 | if (!ivtv_waitscl(itv, 0)) { | ||
242 | IVTV_DEBUG_I2C("Could not set SCL low starting an ack\n"); | ||
243 | return -EREMOTEIO; | ||
244 | } | ||
245 | } | ||
246 | ivtv_setsda(itv, 1); | ||
247 | ivtv_scldelay(itv); | ||
248 | ivtv_setscl(itv, 1); | ||
249 | if (!ivtv_waitsda(itv, 0)) { | ||
250 | IVTV_DEBUG_I2C("Slave did not ack\n"); | ||
251 | ret = -EREMOTEIO; | ||
252 | } | ||
253 | ivtv_setscl(itv, 0); | ||
254 | if (!ivtv_waitscl(itv, 0)) { | ||
255 | IVTV_DEBUG_I2C("Failed to set SCL low after ACK\n"); | ||
256 | ret = -EREMOTEIO; | ||
257 | } | ||
258 | return ret; | ||
259 | } | ||
260 | |||
261 | /* Write a single byte to the i2c bus and wait for the slave to ACK */ | ||
262 | static int ivtv_sendbyte(struct ivtv *itv, unsigned char byte) | ||
263 | { | ||
264 | int i, bit; | ||
265 | |||
266 | IVTV_DEBUG_I2C("write %x\n",byte); | ||
267 | for (i = 0; i < 8; ++i, byte<<=1) { | ||
268 | ivtv_setscl(itv, 0); | ||
269 | if (!ivtv_waitscl(itv, 0)) { | ||
270 | IVTV_DEBUG_I2C("Error setting SCL low\n"); | ||
271 | return -EREMOTEIO; | ||
272 | } | ||
273 | bit = (byte>>7)&1; | ||
274 | ivtv_setsda(itv, bit); | ||
275 | if (!ivtv_waitsda(itv, bit)) { | ||
276 | IVTV_DEBUG_I2C("Error setting SDA\n"); | ||
277 | return -EREMOTEIO; | ||
278 | } | ||
279 | ivtv_setscl(itv, 1); | ||
280 | if (!ivtv_waitscl(itv, 1)) { | ||
281 | IVTV_DEBUG_I2C("Slave not ready for bit\n"); | ||
282 | return -EREMOTEIO; | ||
283 | } | ||
284 | } | ||
285 | ivtv_setscl(itv, 0); | ||
286 | if (!ivtv_waitscl(itv, 0)) { | ||
287 | IVTV_DEBUG_I2C("Error setting SCL low\n"); | ||
288 | return -EREMOTEIO; | ||
289 | } | ||
290 | return ivtv_ack(itv); | ||
291 | } | ||
292 | |||
293 | /* Read a byte from the i2c bus and send a NACK if applicable (i.e. for the | ||
294 | final byte) */ | ||
295 | static int ivtv_readbyte(struct ivtv *itv, unsigned char *byte, int nack) | ||
296 | { | ||
297 | int i; | ||
298 | |||
299 | *byte = 0; | ||
300 | |||
301 | ivtv_setsda(itv, 1); | ||
302 | ivtv_scldelay(itv); | ||
303 | for (i = 0; i < 8; ++i) { | ||
304 | ivtv_setscl(itv, 0); | ||
305 | ivtv_scldelay(itv); | ||
306 | ivtv_setscl(itv, 1); | ||
307 | if (!ivtv_waitscl(itv, 1)) { | ||
308 | IVTV_DEBUG_I2C("Error setting SCL high\n"); | ||
309 | return -EREMOTEIO; | ||
310 | } | ||
311 | *byte = ((*byte)<<1)|ivtv_getsda(itv); | ||
312 | } | ||
313 | ivtv_setscl(itv, 0); | ||
314 | ivtv_scldelay(itv); | ||
315 | ivtv_setsda(itv, nack); | ||
316 | ivtv_scldelay(itv); | ||
317 | ivtv_setscl(itv, 1); | ||
318 | ivtv_scldelay(itv); | ||
319 | ivtv_setscl(itv, 0); | ||
320 | ivtv_scldelay(itv); | ||
321 | IVTV_DEBUG_I2C("read %x\n",*byte); | ||
322 | return 0; | ||
323 | } | ||
324 | |||
325 | /* Issue a start condition on the i2c bus to alert slaves to prepare for | ||
326 | an address write */ | ||
327 | static int ivtv_start(struct ivtv *itv) | ||
328 | { | ||
329 | int sda; | ||
330 | |||
331 | sda = ivtv_getsda(itv); | ||
332 | if (sda != 1) { | ||
333 | IVTV_DEBUG_I2C("SDA was low at start\n"); | ||
334 | ivtv_setsda(itv, 1); | ||
335 | if (!ivtv_waitsda(itv, 1)) { | ||
336 | IVTV_DEBUG_I2C("SDA stuck low\n"); | ||
337 | return -EREMOTEIO; | ||
338 | } | ||
339 | } | ||
340 | if (ivtv_getscl(itv) != 1) { | ||
341 | ivtv_setscl(itv, 1); | ||
342 | if (!ivtv_waitscl(itv, 1)) { | ||
343 | IVTV_DEBUG_I2C("SCL stuck low at start\n"); | ||
344 | return -EREMOTEIO; | ||
345 | } | ||
346 | } | ||
347 | ivtv_setsda(itv, 0); | ||
348 | ivtv_scldelay(itv); | ||
349 | return 0; | ||
350 | } | ||
351 | |||
352 | /* Issue a stop condition on the i2c bus to release it */ | ||
353 | static int ivtv_stop(struct ivtv *itv) | ||
354 | { | ||
355 | int i; | ||
356 | |||
357 | if (ivtv_getscl(itv) != 0) { | ||
358 | IVTV_DEBUG_I2C("SCL not low when stopping\n"); | ||
359 | ivtv_setscl(itv, 0); | ||
360 | if (!ivtv_waitscl(itv, 0)) { | ||
361 | IVTV_DEBUG_I2C("SCL could not be set low\n"); | ||
362 | } | ||
363 | } | ||
364 | ivtv_setsda(itv, 0); | ||
365 | ivtv_scldelay(itv); | ||
366 | ivtv_setscl(itv, 1); | ||
367 | if (!ivtv_waitscl(itv, 1)) { | ||
368 | IVTV_DEBUG_I2C("SCL could not be set high\n"); | ||
369 | return -EREMOTEIO; | ||
370 | } | ||
371 | ivtv_scldelay(itv); | ||
372 | ivtv_setsda(itv, 1); | ||
373 | if (!ivtv_waitsda(itv, 1)) { | ||
374 | IVTV_DEBUG_I2C("resetting I2C\n"); | ||
375 | for (i = 0; i < 16; ++i) { | ||
376 | ivtv_setscl(itv, 0); | ||
377 | ivtv_scldelay(itv); | ||
378 | ivtv_setscl(itv, 1); | ||
379 | ivtv_scldelay(itv); | ||
380 | ivtv_setsda(itv, 1); | ||
381 | } | ||
382 | ivtv_waitsda(itv, 1); | ||
383 | return -EREMOTEIO; | ||
384 | } | ||
385 | return 0; | ||
386 | } | ||
387 | |||
388 | /* Write a message to the given i2c slave. do_stop may be 0 to prevent | ||
389 | issuing the i2c stop condition (when following with a read) */ | ||
390 | static int ivtv_write(struct ivtv *itv, unsigned char addr, unsigned char *data, u32 len, int do_stop) | ||
391 | { | ||
392 | int retry, ret = -EREMOTEIO; | ||
393 | u32 i; | ||
394 | |||
395 | for (retry = 0; ret != 0 && retry < 8; ++retry) { | ||
396 | ret = ivtv_start(itv); | ||
397 | |||
398 | if (ret == 0) { | ||
399 | ret = ivtv_sendbyte(itv, addr<<1); | ||
400 | for (i = 0; ret == 0 && i < len; ++i) | ||
401 | ret = ivtv_sendbyte(itv, data[i]); | ||
402 | } | ||
403 | if (ret != 0 || do_stop) { | ||
404 | ivtv_stop(itv); | ||
405 | } | ||
406 | } | ||
407 | if (ret) | ||
408 | IVTV_DEBUG_I2C("i2c write to %x failed\n", addr); | ||
409 | return ret; | ||
410 | } | ||
411 | |||
412 | /* Read data from the given i2c slave. A stop condition is always issued. */ | ||
413 | static int ivtv_read(struct ivtv *itv, unsigned char addr, unsigned char *data, u32 len) | ||
414 | { | ||
415 | int retry, ret = -EREMOTEIO; | ||
416 | u32 i; | ||
417 | |||
418 | for (retry = 0; ret != 0 && retry < 8; ++retry) { | ||
419 | ret = ivtv_start(itv); | ||
420 | if (ret == 0) | ||
421 | ret = ivtv_sendbyte(itv, (addr << 1) | 1); | ||
422 | for (i = 0; ret == 0 && i < len; ++i) { | ||
423 | ret = ivtv_readbyte(itv, &data[i], i == len - 1); | ||
424 | } | ||
425 | ivtv_stop(itv); | ||
426 | } | ||
427 | if (ret) | ||
428 | IVTV_DEBUG_I2C("i2c read from %x failed\n", addr); | ||
429 | return ret; | ||
430 | } | ||
431 | |||
432 | /* Kernel i2c transfer implementation. Takes a number of messages to be read | ||
433 | or written. If a read follows a write, this will occur without an | ||
434 | intervening stop condition */ | ||
435 | static int ivtv_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) | ||
436 | { | ||
437 | struct ivtv *itv = i2c_get_adapdata(i2c_adap); | ||
438 | int retval; | ||
439 | int i; | ||
440 | |||
441 | mutex_lock(&itv->i2c_bus_lock); | ||
442 | for (i = retval = 0; retval == 0 && i < num; i++) { | ||
443 | if (msgs[i].flags & I2C_M_RD) | ||
444 | retval = ivtv_read(itv, msgs[i].addr, msgs[i].buf, msgs[i].len); | ||
445 | else { | ||
446 | /* if followed by a read, don't stop */ | ||
447 | int stop = !(i + 1 < num && msgs[i + 1].flags == I2C_M_RD); | ||
448 | |||
449 | retval = ivtv_write(itv, msgs[i].addr, msgs[i].buf, msgs[i].len, stop); | ||
450 | } | ||
451 | } | ||
452 | mutex_unlock(&itv->i2c_bus_lock); | ||
453 | return retval ? retval : num; | ||
454 | } | ||
455 | |||
456 | /* Kernel i2c capabilities */ | ||
457 | static u32 ivtv_functionality(struct i2c_adapter *adap) | ||
458 | { | ||
459 | return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; | ||
460 | } | ||
461 | |||
462 | static struct i2c_algorithm ivtv_algo = { | ||
463 | .master_xfer = ivtv_xfer, | ||
464 | .functionality = ivtv_functionality, | ||
465 | }; | ||
466 | |||
467 | /* template for our-bit banger */ | ||
468 | static struct i2c_adapter ivtv_i2c_adap_hw_template = { | ||
469 | .name = "ivtv i2c driver", | ||
470 | .id = I2C_HW_B_CX2341X, | ||
471 | .algo = &ivtv_algo, | ||
472 | .algo_data = NULL, /* filled from template */ | ||
473 | .client_register = attach_inform, | ||
474 | .client_unregister = detach_inform, | ||
475 | .owner = THIS_MODULE, | ||
476 | #ifdef I2C_ADAP_CLASS_TV_ANALOG | ||
477 | .class = I2C_ADAP_CLASS_TV_ANALOG, | ||
478 | #endif | ||
479 | }; | ||
480 | |||
481 | static void ivtv_setscl_old(void *data, int state) | ||
482 | { | ||
483 | struct ivtv *itv = (struct ivtv *)data; | ||
484 | |||
485 | if (state) | ||
486 | itv->i2c_state |= 0x01; | ||
487 | else | ||
488 | itv->i2c_state &= ~0x01; | ||
489 | |||
490 | /* write them out */ | ||
491 | /* write bits are inverted */ | ||
492 | write_reg(~itv->i2c_state, IVTV_REG_I2C_SETSCL_OFFSET); | ||
493 | } | ||
494 | |||
495 | static void ivtv_setsda_old(void *data, int state) | ||
496 | { | ||
497 | struct ivtv *itv = (struct ivtv *)data; | ||
498 | |||
499 | if (state) | ||
500 | itv->i2c_state |= 0x01; | ||
501 | else | ||
502 | itv->i2c_state &= ~0x01; | ||
503 | |||
504 | /* write them out */ | ||
505 | /* write bits are inverted */ | ||
506 | write_reg(~itv->i2c_state, IVTV_REG_I2C_SETSDA_OFFSET); | ||
507 | } | ||
508 | |||
509 | static int ivtv_getscl_old(void *data) | ||
510 | { | ||
511 | struct ivtv *itv = (struct ivtv *)data; | ||
512 | |||
513 | return read_reg(IVTV_REG_I2C_GETSCL_OFFSET) & 1; | ||
514 | } | ||
515 | |||
516 | static int ivtv_getsda_old(void *data) | ||
517 | { | ||
518 | struct ivtv *itv = (struct ivtv *)data; | ||
519 | |||
520 | return read_reg(IVTV_REG_I2C_GETSDA_OFFSET) & 1; | ||
521 | } | ||
522 | |||
523 | /* template for i2c-bit-algo */ | ||
524 | static struct i2c_adapter ivtv_i2c_adap_template = { | ||
525 | .name = "ivtv i2c driver", | ||
526 | .id = I2C_HW_B_CX2341X, /* algo-bit is OR'd with this */ | ||
527 | .algo = NULL, /* set by i2c-algo-bit */ | ||
528 | .algo_data = NULL, /* filled from template */ | ||
529 | .client_register = attach_inform, | ||
530 | .client_unregister = detach_inform, | ||
531 | .owner = THIS_MODULE, | ||
532 | #ifdef I2C_ADAP_CLASS_TV_ANALOG | ||
533 | .class = I2C_ADAP_CLASS_TV_ANALOG, | ||
534 | #endif | ||
535 | }; | ||
536 | |||
537 | static struct i2c_algo_bit_data ivtv_i2c_algo_template = { | ||
538 | NULL, /* ?? */ | ||
539 | ivtv_setsda_old, /* setsda function */ | ||
540 | ivtv_setscl_old, /* " */ | ||
541 | ivtv_getsda_old, /* " */ | ||
542 | ivtv_getscl_old, /* " */ | ||
543 | 10, /* udelay */ | ||
544 | 200 /* timeout */ | ||
545 | }; | ||
546 | |||
547 | static struct i2c_client ivtv_i2c_client_template = { | ||
548 | .name = "ivtv internal", | ||
549 | }; | ||
550 | |||
551 | int ivtv_call_i2c_client(struct ivtv *itv, int addr, unsigned int cmd, void *arg) | ||
552 | { | ||
553 | struct i2c_client *client; | ||
554 | int retval; | ||
555 | int i; | ||
556 | |||
557 | IVTV_DEBUG_I2C("call_i2c_client addr=%02x\n", addr); | ||
558 | for (i = 0; i < I2C_CLIENTS_MAX; i++) { | ||
559 | client = itv->i2c_clients[i]; | ||
560 | if (client == NULL) { | ||
561 | continue; | ||
562 | } | ||
563 | if (client->driver->command == NULL) { | ||
564 | continue; | ||
565 | } | ||
566 | if (addr == client->addr) { | ||
567 | retval = client->driver->command(client, cmd, arg); | ||
568 | return retval; | ||
569 | } | ||
570 | } | ||
571 | if (cmd != VIDIOC_G_CHIP_IDENT) | ||
572 | IVTV_ERR("i2c addr 0x%02x not found for command 0x%x!\n", addr, cmd); | ||
573 | return -ENODEV; | ||
574 | } | ||
575 | |||
576 | /* Find the i2c device based on the driver ID and return | ||
577 | its i2c address or -ENODEV if no matching device was found. */ | ||
578 | static int ivtv_i2c_id_addr(struct ivtv *itv, u32 id) | ||
579 | { | ||
580 | struct i2c_client *client; | ||
581 | int retval = -ENODEV; | ||
582 | int i; | ||
583 | |||
584 | for (i = 0; i < I2C_CLIENTS_MAX; i++) { | ||
585 | client = itv->i2c_clients[i]; | ||
586 | if (client == NULL) | ||
587 | continue; | ||
588 | if (id == client->driver->id) { | ||
589 | retval = client->addr; | ||
590 | break; | ||
591 | } | ||
592 | } | ||
593 | return retval; | ||
594 | } | ||
595 | |||
596 | /* Find the i2c device name matching the DRIVERID */ | ||
597 | static const char *ivtv_i2c_id_name(u32 id) | ||
598 | { | ||
599 | int i; | ||
600 | |||
601 | for (i = 0; i < ARRAY_SIZE(hw_driverids); i++) | ||
602 | if (hw_driverids[i] == id) | ||
603 | return hw_drivernames[i]; | ||
604 | return "unknown device"; | ||
605 | } | ||
606 | |||
607 | /* Find the i2c device name matching the IVTV_HW_ flag */ | ||
608 | static const char *ivtv_i2c_hw_name(u32 hw) | ||
609 | { | ||
610 | int i; | ||
611 | |||
612 | for (i = 0; i < ARRAY_SIZE(hw_driverids); i++) | ||
613 | if (1 << i == hw) | ||
614 | return hw_drivernames[i]; | ||
615 | return "unknown device"; | ||
616 | } | ||
617 | |||
618 | /* Find the i2c device matching the IVTV_HW_ flag and return | ||
619 | its i2c address or -ENODEV if no matching device was found. */ | ||
620 | int ivtv_i2c_hw_addr(struct ivtv *itv, u32 hw) | ||
621 | { | ||
622 | int i; | ||
623 | |||
624 | for (i = 0; i < ARRAY_SIZE(hw_driverids); i++) | ||
625 | if (1 << i == hw) | ||
626 | return ivtv_i2c_id_addr(itv, hw_driverids[i]); | ||
627 | return -ENODEV; | ||
628 | } | ||
629 | |||
630 | /* Calls i2c device based on IVTV_HW_ flag. If hw == 0, then do nothing. | ||
631 | If hw == IVTV_HW_GPIO then call the gpio handler. */ | ||
632 | int ivtv_i2c_hw(struct ivtv *itv, u32 hw, unsigned int cmd, void *arg) | ||
633 | { | ||
634 | int addr; | ||
635 | |||
636 | if (hw == IVTV_HW_GPIO) | ||
637 | return ivtv_gpio(itv, cmd, arg); | ||
638 | if (hw == 0) | ||
639 | return 0; | ||
640 | |||
641 | addr = ivtv_i2c_hw_addr(itv, hw); | ||
642 | if (addr < 0) { | ||
643 | IVTV_ERR("i2c hardware 0x%08x (%s) not found for command 0x%x!\n", | ||
644 | hw, ivtv_i2c_hw_name(hw), cmd); | ||
645 | return addr; | ||
646 | } | ||
647 | return ivtv_call_i2c_client(itv, addr, cmd, arg); | ||
648 | } | ||
649 | |||
650 | /* Calls i2c device based on I2C driver ID. */ | ||
651 | int ivtv_i2c_id(struct ivtv *itv, u32 id, unsigned int cmd, void *arg) | ||
652 | { | ||
653 | int addr; | ||
654 | |||
655 | addr = ivtv_i2c_id_addr(itv, id); | ||
656 | if (addr < 0) { | ||
657 | if (cmd != VIDIOC_G_CHIP_IDENT) | ||
658 | IVTV_ERR("i2c ID 0x%08x (%s) not found for command 0x%x!\n", | ||
659 | id, ivtv_i2c_id_name(id), cmd); | ||
660 | return addr; | ||
661 | } | ||
662 | return ivtv_call_i2c_client(itv, addr, cmd, arg); | ||
663 | } | ||
664 | |||
665 | int ivtv_cx25840(struct ivtv *itv, unsigned int cmd, void *arg) | ||
666 | { | ||
667 | return ivtv_call_i2c_client(itv, IVTV_CX25840_I2C_ADDR, cmd, arg); | ||
668 | } | ||
669 | |||
670 | int ivtv_saa7115(struct ivtv *itv, unsigned int cmd, void *arg) | ||
671 | { | ||
672 | return ivtv_call_i2c_client(itv, IVTV_SAA7115_I2C_ADDR, cmd, arg); | ||
673 | } | ||
674 | |||
675 | int ivtv_saa7127(struct ivtv *itv, unsigned int cmd, void *arg) | ||
676 | { | ||
677 | return ivtv_call_i2c_client(itv, IVTV_SAA7127_I2C_ADDR, cmd, arg); | ||
678 | } | ||
679 | |||
680 | int ivtv_saa717x(struct ivtv *itv, unsigned int cmd, void *arg) | ||
681 | { | ||
682 | return ivtv_call_i2c_client(itv, IVTV_SAA717x_I2C_ADDR, cmd, arg); | ||
683 | } | ||
684 | |||
685 | int ivtv_upd64031a(struct ivtv *itv, unsigned int cmd, void *arg) | ||
686 | { | ||
687 | return ivtv_call_i2c_client(itv, IVTV_UPD64031A_I2C_ADDR, cmd, arg); | ||
688 | } | ||
689 | |||
690 | int ivtv_upd64083(struct ivtv *itv, unsigned int cmd, void *arg) | ||
691 | { | ||
692 | return ivtv_call_i2c_client(itv, IVTV_UPD64083_I2C_ADDR, cmd, arg); | ||
693 | } | ||
694 | |||
695 | /* broadcast cmd for all I2C clients and for the gpio subsystem */ | ||
696 | void ivtv_call_i2c_clients(struct ivtv *itv, unsigned int cmd, void *arg) | ||
697 | { | ||
698 | if (itv->i2c_adap.algo == NULL) { | ||
699 | IVTV_ERR("adapter is not set"); | ||
700 | return; | ||
701 | } | ||
702 | i2c_clients_command(&itv->i2c_adap, cmd, arg); | ||
703 | if (itv->hw_flags & IVTV_HW_GPIO) | ||
704 | ivtv_gpio(itv, cmd, arg); | ||
705 | } | ||
706 | |||
707 | /* init + register i2c algo-bit adapter */ | ||
708 | int __devinit init_ivtv_i2c(struct ivtv *itv) | ||
709 | { | ||
710 | IVTV_DEBUG_I2C("i2c init\n"); | ||
711 | |||
712 | if (itv->options.newi2c > 0) { | ||
713 | memcpy(&itv->i2c_adap, &ivtv_i2c_adap_hw_template, | ||
714 | sizeof(struct i2c_adapter)); | ||
715 | } else { | ||
716 | memcpy(&itv->i2c_adap, &ivtv_i2c_adap_template, | ||
717 | sizeof(struct i2c_adapter)); | ||
718 | memcpy(&itv->i2c_algo, &ivtv_i2c_algo_template, | ||
719 | sizeof(struct i2c_algo_bit_data)); | ||
720 | itv->i2c_algo.data = itv; | ||
721 | itv->i2c_adap.algo_data = &itv->i2c_algo; | ||
722 | } | ||
723 | |||
724 | sprintf(itv->i2c_adap.name + strlen(itv->i2c_adap.name), " #%d", | ||
725 | itv->num); | ||
726 | i2c_set_adapdata(&itv->i2c_adap, itv); | ||
727 | |||
728 | memcpy(&itv->i2c_client, &ivtv_i2c_client_template, | ||
729 | sizeof(struct i2c_client)); | ||
730 | itv->i2c_client.adapter = &itv->i2c_adap; | ||
731 | itv->i2c_adap.dev.parent = &itv->dev->dev; | ||
732 | |||
733 | IVTV_DEBUG_I2C("setting scl and sda to 1\n"); | ||
734 | ivtv_setscl(itv, 1); | ||
735 | ivtv_setsda(itv, 1); | ||
736 | |||
737 | if (itv->options.newi2c > 0) | ||
738 | return i2c_add_adapter(&itv->i2c_adap); | ||
739 | else | ||
740 | return i2c_bit_add_bus(&itv->i2c_adap); | ||
741 | } | ||
742 | |||
743 | void __devexit exit_ivtv_i2c(struct ivtv *itv) | ||
744 | { | ||
745 | IVTV_DEBUG_I2C("i2c exit\n"); | ||
746 | |||
747 | i2c_del_adapter(&itv->i2c_adap); | ||
748 | } | ||
diff --git a/drivers/media/video/ivtv/ivtv-i2c.h b/drivers/media/video/ivtv/ivtv-i2c.h new file mode 100644 index 000000000000..5d210adb5c52 --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-i2c.h | |||
@@ -0,0 +1,36 @@ | |||
1 | /* | ||
2 | I2C functions | ||
3 | Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> | ||
4 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | int ivtv_cx25840(struct ivtv *itv, unsigned int cmd, void *arg); | ||
22 | int ivtv_saa7115(struct ivtv *itv, unsigned int cmd, void *arg); | ||
23 | int ivtv_saa7127(struct ivtv *itv, unsigned int cmd, void *arg); | ||
24 | int ivtv_saa717x(struct ivtv *itv, unsigned int cmd, void *arg); | ||
25 | int ivtv_upd64031a(struct ivtv *itv, unsigned int cmd, void *arg); | ||
26 | int ivtv_upd64083(struct ivtv *itv, unsigned int cmd, void *arg); | ||
27 | |||
28 | int ivtv_i2c_hw_addr(struct ivtv *itv, u32 hw); | ||
29 | int ivtv_i2c_hw(struct ivtv *itv, u32 hw, unsigned int cmd, void *arg); | ||
30 | int ivtv_i2c_id(struct ivtv *itv, u32 id, unsigned int cmd, void *arg); | ||
31 | int ivtv_call_i2c_client(struct ivtv *itv, int addr, unsigned int cmd, void *arg); | ||
32 | void ivtv_call_i2c_clients(struct ivtv *itv, unsigned int cmd, void *arg); | ||
33 | |||
34 | /* init + register i2c algo-bit adapter */ | ||
35 | int __devinit init_ivtv_i2c(struct ivtv *itv); | ||
36 | void __devexit exit_ivtv_i2c(struct ivtv *itv); | ||
diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c new file mode 100644 index 000000000000..794a6a02f82f --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-ioctl.c | |||
@@ -0,0 +1,1567 @@ | |||
1 | /* | ||
2 | ioctl system call | ||
3 | Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> | ||
4 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | #include "ivtv-driver.h" | ||
22 | #include "ivtv-version.h" | ||
23 | #include "ivtv-mailbox.h" | ||
24 | #include "ivtv-i2c.h" | ||
25 | #include "ivtv-queue.h" | ||
26 | #include "ivtv-fileops.h" | ||
27 | #include "ivtv-vbi.h" | ||
28 | #include "ivtv-audio.h" | ||
29 | #include "ivtv-video.h" | ||
30 | #include "ivtv-streams.h" | ||
31 | #include "ivtv-yuv.h" | ||
32 | #include "ivtv-ioctl.h" | ||
33 | #include "ivtv-gpio.h" | ||
34 | #include "ivtv-controls.h" | ||
35 | #include "ivtv-cards.h" | ||
36 | #include <media/saa7127.h> | ||
37 | #include <media/tveeprom.h> | ||
38 | #include <media/v4l2-chip-ident.h> | ||
39 | #include <linux/dvb/audio.h> | ||
40 | #include <linux/i2c-id.h> | ||
41 | |||
42 | u16 service2vbi(int type) | ||
43 | { | ||
44 | switch (type) { | ||
45 | case V4L2_SLICED_TELETEXT_B: | ||
46 | return IVTV_SLICED_TYPE_TELETEXT_B; | ||
47 | case V4L2_SLICED_CAPTION_525: | ||
48 | return IVTV_SLICED_TYPE_CAPTION_525; | ||
49 | case V4L2_SLICED_WSS_625: | ||
50 | return IVTV_SLICED_TYPE_WSS_625; | ||
51 | case V4L2_SLICED_VPS: | ||
52 | return IVTV_SLICED_TYPE_VPS; | ||
53 | default: | ||
54 | return 0; | ||
55 | } | ||
56 | } | ||
57 | |||
58 | static int valid_service_line(int field, int line, int is_pal) | ||
59 | { | ||
60 | return (is_pal && line >= 6 && (line != 23 || field == 0)) || | ||
61 | (!is_pal && line >= 10 && line < 22); | ||
62 | } | ||
63 | |||
64 | static u16 select_service_from_set(int field, int line, u16 set, int is_pal) | ||
65 | { | ||
66 | u16 valid_set = (is_pal ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525); | ||
67 | int i; | ||
68 | |||
69 | set = set & valid_set; | ||
70 | if (set == 0 || !valid_service_line(field, line, is_pal)) { | ||
71 | return 0; | ||
72 | } | ||
73 | if (!is_pal) { | ||
74 | if (line == 21 && (set & V4L2_SLICED_CAPTION_525)) | ||
75 | return V4L2_SLICED_CAPTION_525; | ||
76 | } | ||
77 | else { | ||
78 | if (line == 16 && field == 0 && (set & V4L2_SLICED_VPS)) | ||
79 | return V4L2_SLICED_VPS; | ||
80 | if (line == 23 && field == 0 && (set & V4L2_SLICED_WSS_625)) | ||
81 | return V4L2_SLICED_WSS_625; | ||
82 | if (line == 23) | ||
83 | return 0; | ||
84 | } | ||
85 | for (i = 0; i < 32; i++) { | ||
86 | if ((1 << i) & set) | ||
87 | return 1 << i; | ||
88 | } | ||
89 | return 0; | ||
90 | } | ||
91 | |||
92 | void expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal) | ||
93 | { | ||
94 | u16 set = fmt->service_set; | ||
95 | int f, l; | ||
96 | |||
97 | fmt->service_set = 0; | ||
98 | for (f = 0; f < 2; f++) { | ||
99 | for (l = 0; l < 24; l++) { | ||
100 | fmt->service_lines[f][l] = select_service_from_set(f, l, set, is_pal); | ||
101 | } | ||
102 | } | ||
103 | } | ||
104 | |||
105 | static int check_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal) | ||
106 | { | ||
107 | int f, l; | ||
108 | u16 set = 0; | ||
109 | |||
110 | for (f = 0; f < 2; f++) { | ||
111 | for (l = 0; l < 24; l++) { | ||
112 | fmt->service_lines[f][l] = select_service_from_set(f, l, fmt->service_lines[f][l], is_pal); | ||
113 | set |= fmt->service_lines[f][l]; | ||
114 | } | ||
115 | } | ||
116 | return set != 0; | ||
117 | } | ||
118 | |||
119 | u16 get_service_set(struct v4l2_sliced_vbi_format *fmt) | ||
120 | { | ||
121 | int f, l; | ||
122 | u16 set = 0; | ||
123 | |||
124 | for (f = 0; f < 2; f++) { | ||
125 | for (l = 0; l < 24; l++) { | ||
126 | set |= fmt->service_lines[f][l]; | ||
127 | } | ||
128 | } | ||
129 | return set; | ||
130 | } | ||
131 | |||
132 | static const struct { | ||
133 | v4l2_std_id std; | ||
134 | char *name; | ||
135 | } enum_stds[] = { | ||
136 | { V4L2_STD_PAL_BG | V4L2_STD_PAL_H, "PAL-BGH" }, | ||
137 | { V4L2_STD_PAL_DK, "PAL-DK" }, | ||
138 | { V4L2_STD_PAL_I, "PAL-I" }, | ||
139 | { V4L2_STD_PAL_M, "PAL-M" }, | ||
140 | { V4L2_STD_PAL_N, "PAL-N" }, | ||
141 | { V4L2_STD_PAL_Nc, "PAL-Nc" }, | ||
142 | { V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H, "SECAM-BGH" }, | ||
143 | { V4L2_STD_SECAM_DK, "SECAM-DK" }, | ||
144 | { V4L2_STD_SECAM_L, "SECAM-L" }, | ||
145 | { V4L2_STD_SECAM_LC, "SECAM-L'" }, | ||
146 | { V4L2_STD_NTSC_M, "NTSC-M" }, | ||
147 | { V4L2_STD_NTSC_M_JP, "NTSC-J" }, | ||
148 | { V4L2_STD_NTSC_M_KR, "NTSC-K" }, | ||
149 | }; | ||
150 | |||
151 | static const struct v4l2_standard ivtv_std_60hz = | ||
152 | { | ||
153 | .frameperiod = {.numerator = 1001, .denominator = 30000}, | ||
154 | .framelines = 525, | ||
155 | }; | ||
156 | |||
157 | static const struct v4l2_standard ivtv_std_50hz = | ||
158 | { | ||
159 | .frameperiod = {.numerator = 1, .denominator = 25}, | ||
160 | .framelines = 625, | ||
161 | }; | ||
162 | |||
163 | void ivtv_set_osd_alpha(struct ivtv *itv) | ||
164 | { | ||
165 | ivtv_vapi(itv, CX2341X_OSD_SET_GLOBAL_ALPHA, 3, | ||
166 | itv->osd_global_alpha_state, itv->osd_global_alpha, !itv->osd_local_alpha_state); | ||
167 | ivtv_vapi(itv, CX2341X_OSD_SET_CHROMA_KEY, 2, itv->osd_color_key_state, itv->osd_color_key); | ||
168 | } | ||
169 | |||
170 | int ivtv_set_speed(struct ivtv *itv, int speed) | ||
171 | { | ||
172 | u32 data[CX2341X_MBOX_MAX_DATA]; | ||
173 | struct ivtv_stream *s; | ||
174 | int single_step = (speed == 1 || speed == -1); | ||
175 | DEFINE_WAIT(wait); | ||
176 | |||
177 | if (speed == 0) speed = 1000; | ||
178 | |||
179 | /* No change? */ | ||
180 | if (speed == itv->speed && !single_step) | ||
181 | return 0; | ||
182 | |||
183 | s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG]; | ||
184 | |||
185 | if (single_step && (speed < 0) == (itv->speed < 0)) { | ||
186 | /* Single step video and no need to change direction */ | ||
187 | ivtv_vapi(itv, CX2341X_DEC_STEP_VIDEO, 1, 0); | ||
188 | itv->speed = speed; | ||
189 | return 0; | ||
190 | } | ||
191 | if (single_step) | ||
192 | /* Need to change direction */ | ||
193 | speed = speed < 0 ? -1000 : 1000; | ||
194 | |||
195 | data[0] = (speed > 1000 || speed < -1000) ? 0x80000000 : 0; | ||
196 | data[0] |= (speed > 1000 || speed < -1500) ? 0x40000000 : 0; | ||
197 | data[1] = (speed < 0); | ||
198 | data[2] = speed < 0 ? 3 : 7; | ||
199 | data[3] = itv->params.video_b_frames; | ||
200 | data[4] = (speed == 1500 || speed == 500) ? itv->speed_mute_audio : 0; | ||
201 | data[5] = 0; | ||
202 | data[6] = 0; | ||
203 | |||
204 | if (speed == 1500 || speed == -1500) data[0] |= 1; | ||
205 | else if (speed == 2000 || speed == -2000) data[0] |= 2; | ||
206 | else if (speed > -1000 && speed < 0) data[0] |= (-1000 / speed); | ||
207 | else if (speed < 1000 && speed > 0) data[0] |= (1000 / speed); | ||
208 | |||
209 | /* If not decoding, just change speed setting */ | ||
210 | if (atomic_read(&itv->decoding) > 0) { | ||
211 | int got_sig = 0; | ||
212 | |||
213 | /* Stop all DMA and decoding activity */ | ||
214 | ivtv_vapi(itv, CX2341X_DEC_PAUSE_PLAYBACK, 1, 0); | ||
215 | |||
216 | /* Wait for any DMA to finish */ | ||
217 | prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE); | ||
218 | while (itv->i_flags & IVTV_F_I_DMA) { | ||
219 | got_sig = signal_pending(current); | ||
220 | if (got_sig) | ||
221 | break; | ||
222 | got_sig = 0; | ||
223 | schedule(); | ||
224 | } | ||
225 | finish_wait(&itv->dma_waitq, &wait); | ||
226 | if (got_sig) | ||
227 | return -EINTR; | ||
228 | |||
229 | /* Change Speed safely */ | ||
230 | ivtv_api(itv, CX2341X_DEC_SET_PLAYBACK_SPEED, 7, data); | ||
231 | IVTV_DEBUG_INFO("Setting Speed to 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", | ||
232 | data[0], data[1], data[2], data[3], data[4], data[5], data[6]); | ||
233 | } | ||
234 | if (single_step) { | ||
235 | speed = (speed < 0) ? -1 : 1; | ||
236 | ivtv_vapi(itv, CX2341X_DEC_STEP_VIDEO, 1, 0); | ||
237 | } | ||
238 | itv->speed = speed; | ||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | static int ivtv_validate_speed(int cur_speed, int new_speed) | ||
243 | { | ||
244 | int fact = new_speed < 0 ? -1 : 1; | ||
245 | int s; | ||
246 | |||
247 | if (new_speed < 0) new_speed = -new_speed; | ||
248 | if (cur_speed < 0) cur_speed = -cur_speed; | ||
249 | |||
250 | if (cur_speed <= new_speed) { | ||
251 | if (new_speed > 1500) return fact * 2000; | ||
252 | if (new_speed > 1000) return fact * 1500; | ||
253 | } | ||
254 | else { | ||
255 | if (new_speed >= 2000) return fact * 2000; | ||
256 | if (new_speed >= 1500) return fact * 1500; | ||
257 | if (new_speed >= 1000) return fact * 1000; | ||
258 | } | ||
259 | if (new_speed == 0) return 1000; | ||
260 | if (new_speed == 1 || new_speed == 1000) return fact * new_speed; | ||
261 | |||
262 | s = new_speed; | ||
263 | new_speed = 1000 / new_speed; | ||
264 | if (1000 / cur_speed == new_speed) | ||
265 | new_speed += (cur_speed < s) ? -1 : 1; | ||
266 | if (new_speed > 60) return 1000 / (fact * 60); | ||
267 | return 1000 / (fact * new_speed); | ||
268 | } | ||
269 | |||
270 | static int ivtv_video_command(struct ivtv *itv, struct ivtv_open_id *id, | ||
271 | struct video_command *vc, int try) | ||
272 | { | ||
273 | struct ivtv_stream *s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG]; | ||
274 | |||
275 | if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) | ||
276 | return -EINVAL; | ||
277 | |||
278 | switch (vc->cmd) { | ||
279 | case VIDEO_CMD_PLAY: { | ||
280 | vc->flags = 0; | ||
281 | vc->play.speed = ivtv_validate_speed(itv->speed, vc->play.speed); | ||
282 | if (vc->play.speed < 0) | ||
283 | vc->play.format = VIDEO_PLAY_FMT_GOP; | ||
284 | if (try) break; | ||
285 | |||
286 | if (ivtv_set_output_mode(itv, OUT_MPG) != OUT_MPG) | ||
287 | return -EBUSY; | ||
288 | return ivtv_start_decoding(id, vc->play.speed); | ||
289 | } | ||
290 | |||
291 | case VIDEO_CMD_STOP: | ||
292 | vc->flags &= VIDEO_CMD_STOP_IMMEDIATELY|VIDEO_CMD_STOP_TO_BLACK; | ||
293 | if (vc->flags & VIDEO_CMD_STOP_IMMEDIATELY) | ||
294 | vc->stop.pts = 0; | ||
295 | if (try) break; | ||
296 | if (atomic_read(&itv->decoding) == 0) | ||
297 | return 0; | ||
298 | if (itv->output_mode != OUT_MPG) | ||
299 | return -EBUSY; | ||
300 | |||
301 | itv->output_mode = OUT_NONE; | ||
302 | return ivtv_stop_v4l2_decode_stream(s, vc->flags, vc->stop.pts); | ||
303 | |||
304 | case VIDEO_CMD_FREEZE: | ||
305 | vc->flags &= VIDEO_CMD_FREEZE_TO_BLACK; | ||
306 | if (try) break; | ||
307 | if (itv->output_mode != OUT_MPG) | ||
308 | return -EBUSY; | ||
309 | if (atomic_read(&itv->decoding) > 0) { | ||
310 | ivtv_vapi(itv, CX2341X_DEC_PAUSE_PLAYBACK, 1, | ||
311 | (vc->flags & VIDEO_CMD_FREEZE_TO_BLACK) ? 1 : 0); | ||
312 | } | ||
313 | break; | ||
314 | |||
315 | case VIDEO_CMD_CONTINUE: | ||
316 | vc->flags = 0; | ||
317 | if (try) break; | ||
318 | if (itv->output_mode != OUT_MPG) | ||
319 | return -EBUSY; | ||
320 | if (atomic_read(&itv->decoding) > 0) { | ||
321 | ivtv_vapi(itv, CX2341X_DEC_START_PLAYBACK, 2, 0, 0); | ||
322 | } | ||
323 | break; | ||
324 | |||
325 | default: | ||
326 | return -EINVAL; | ||
327 | } | ||
328 | return 0; | ||
329 | } | ||
330 | |||
331 | static int ivtv_itvc(struct ivtv *itv, unsigned int cmd, void *arg) | ||
332 | { | ||
333 | struct v4l2_register *regs = arg; | ||
334 | unsigned long flags; | ||
335 | volatile u8 __iomem *reg_start; | ||
336 | |||
337 | if (!capable(CAP_SYS_ADMIN)) | ||
338 | return -EPERM; | ||
339 | if (regs->reg >= IVTV_REG_OFFSET && regs->reg < IVTV_REG_OFFSET + IVTV_REG_SIZE) | ||
340 | reg_start = itv->reg_mem - IVTV_REG_OFFSET; | ||
341 | else if (itv->has_cx23415 && regs->reg >= IVTV_DECODER_OFFSET && | ||
342 | regs->reg < IVTV_DECODER_OFFSET + IVTV_DECODER_SIZE) | ||
343 | reg_start = itv->dec_mem - IVTV_DECODER_OFFSET; | ||
344 | else if (regs->reg >= 0 && regs->reg < IVTV_ENCODER_SIZE) | ||
345 | reg_start = itv->enc_mem; | ||
346 | else | ||
347 | return -EINVAL; | ||
348 | |||
349 | spin_lock_irqsave(&ivtv_cards_lock, flags); | ||
350 | if (cmd == VIDIOC_DBG_G_REGISTER) { | ||
351 | regs->val = readl(regs->reg + reg_start); | ||
352 | } else { | ||
353 | writel(regs->val, regs->reg + reg_start); | ||
354 | } | ||
355 | spin_unlock_irqrestore(&ivtv_cards_lock, flags); | ||
356 | return 0; | ||
357 | } | ||
358 | |||
359 | static int ivtv_get_fmt(struct ivtv *itv, int streamtype, struct v4l2_format *fmt) | ||
360 | { | ||
361 | switch (fmt->type) { | ||
362 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: | ||
363 | if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) | ||
364 | return -EINVAL; | ||
365 | fmt->fmt.pix.left = itv->main_rect.left; | ||
366 | fmt->fmt.pix.top = itv->main_rect.top; | ||
367 | fmt->fmt.pix.width = itv->main_rect.width; | ||
368 | fmt->fmt.pix.height = itv->main_rect.height; | ||
369 | fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; | ||
370 | fmt->fmt.pix.field = V4L2_FIELD_INTERLACED; | ||
371 | if (itv->output_mode == OUT_UDMA_YUV) { | ||
372 | switch (itv->yuv_info.lace_mode & IVTV_YUV_MODE_MASK) { | ||
373 | case IVTV_YUV_MODE_INTERLACED: | ||
374 | fmt->fmt.pix.field = (itv->yuv_info.lace_mode & IVTV_YUV_SYNC_MASK) ? | ||
375 | V4L2_FIELD_INTERLACED_BT : V4L2_FIELD_INTERLACED_TB; | ||
376 | break; | ||
377 | case IVTV_YUV_MODE_PROGRESSIVE: | ||
378 | fmt->fmt.pix.field = V4L2_FIELD_NONE; | ||
379 | break; | ||
380 | default: | ||
381 | fmt->fmt.pix.field = V4L2_FIELD_ANY; | ||
382 | break; | ||
383 | } | ||
384 | fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12; | ||
385 | /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */ | ||
386 | fmt->fmt.pix.sizeimage = | ||
387 | fmt->fmt.pix.height * fmt->fmt.pix.width + | ||
388 | fmt->fmt.pix.height * (fmt->fmt.pix.width / 2); | ||
389 | } | ||
390 | else if (itv->output_mode == OUT_YUV || | ||
391 | streamtype == IVTV_ENC_STREAM_TYPE_YUV || | ||
392 | streamtype == IVTV_DEC_STREAM_TYPE_YUV) { | ||
393 | fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12; | ||
394 | /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */ | ||
395 | fmt->fmt.pix.sizeimage = | ||
396 | fmt->fmt.pix.height * fmt->fmt.pix.width + | ||
397 | fmt->fmt.pix.height * (fmt->fmt.pix.width / 2); | ||
398 | } else { | ||
399 | fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; | ||
400 | fmt->fmt.pix.sizeimage = 128 * 1024; | ||
401 | } | ||
402 | break; | ||
403 | |||
404 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | ||
405 | fmt->fmt.pix.left = 0; | ||
406 | fmt->fmt.pix.top = 0; | ||
407 | fmt->fmt.pix.width = itv->params.width; | ||
408 | fmt->fmt.pix.height = itv->params.height; | ||
409 | fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; | ||
410 | fmt->fmt.pix.field = V4L2_FIELD_INTERLACED; | ||
411 | if (streamtype == IVTV_ENC_STREAM_TYPE_YUV || | ||
412 | streamtype == IVTV_DEC_STREAM_TYPE_YUV) { | ||
413 | fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12; | ||
414 | /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */ | ||
415 | fmt->fmt.pix.sizeimage = | ||
416 | fmt->fmt.pix.height * fmt->fmt.pix.width + | ||
417 | fmt->fmt.pix.height * (fmt->fmt.pix.width / 2); | ||
418 | } else { | ||
419 | fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; | ||
420 | fmt->fmt.pix.sizeimage = 128 * 1024; | ||
421 | } | ||
422 | break; | ||
423 | |||
424 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: | ||
425 | if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) | ||
426 | return -EINVAL; | ||
427 | fmt->fmt.win.chromakey = itv->osd_color_key; | ||
428 | fmt->fmt.win.global_alpha = itv->osd_global_alpha; | ||
429 | break; | ||
430 | |||
431 | case V4L2_BUF_TYPE_VBI_CAPTURE: | ||
432 | fmt->fmt.vbi.sampling_rate = 27000000; | ||
433 | fmt->fmt.vbi.offset = 248; | ||
434 | fmt->fmt.vbi.samples_per_line = itv->vbi.raw_decoder_line_size - 4; | ||
435 | fmt->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; | ||
436 | fmt->fmt.vbi.start[0] = itv->vbi.start[0]; | ||
437 | fmt->fmt.vbi.start[1] = itv->vbi.start[1]; | ||
438 | fmt->fmt.vbi.count[0] = fmt->fmt.vbi.count[1] = itv->vbi.count; | ||
439 | break; | ||
440 | |||
441 | case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: | ||
442 | { | ||
443 | struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; | ||
444 | |||
445 | if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_OUTPUT)) | ||
446 | return -EINVAL; | ||
447 | vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; | ||
448 | memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved)); | ||
449 | memset(vbifmt->service_lines, 0, sizeof(vbifmt->service_lines)); | ||
450 | if (itv->is_60hz) { | ||
451 | vbifmt->service_lines[0][21] = V4L2_SLICED_CAPTION_525; | ||
452 | vbifmt->service_lines[1][21] = V4L2_SLICED_CAPTION_525; | ||
453 | } else { | ||
454 | vbifmt->service_lines[0][23] = V4L2_SLICED_WSS_625; | ||
455 | vbifmt->service_lines[0][16] = V4L2_SLICED_VPS; | ||
456 | } | ||
457 | vbifmt->service_set = get_service_set(vbifmt); | ||
458 | break; | ||
459 | } | ||
460 | |||
461 | case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: | ||
462 | { | ||
463 | struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; | ||
464 | |||
465 | vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; | ||
466 | memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved)); | ||
467 | memset(vbifmt->service_lines, 0, sizeof(vbifmt->service_lines)); | ||
468 | |||
469 | if (streamtype == IVTV_DEC_STREAM_TYPE_VBI) { | ||
470 | vbifmt->service_set = itv->is_50hz ? V4L2_SLICED_VBI_625 : | ||
471 | V4L2_SLICED_VBI_525; | ||
472 | expand_service_set(vbifmt, itv->is_50hz); | ||
473 | break; | ||
474 | } | ||
475 | |||
476 | itv->video_dec_func(itv, VIDIOC_G_FMT, fmt); | ||
477 | vbifmt->service_set = get_service_set(vbifmt); | ||
478 | break; | ||
479 | } | ||
480 | case V4L2_BUF_TYPE_VBI_OUTPUT: | ||
481 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: | ||
482 | default: | ||
483 | return -EINVAL; | ||
484 | } | ||
485 | return 0; | ||
486 | } | ||
487 | |||
488 | static int ivtv_try_or_set_fmt(struct ivtv *itv, int streamtype, | ||
489 | struct v4l2_format *fmt, int set_fmt) | ||
490 | { | ||
491 | struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; | ||
492 | u16 set; | ||
493 | |||
494 | if (fmt->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { | ||
495 | struct v4l2_rect r; | ||
496 | int field; | ||
497 | |||
498 | if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) | ||
499 | return -EINVAL; | ||
500 | field = fmt->fmt.pix.field; | ||
501 | r.top = fmt->fmt.pix.top; | ||
502 | r.left = fmt->fmt.pix.left; | ||
503 | r.width = fmt->fmt.pix.width; | ||
504 | r.height = fmt->fmt.pix.height; | ||
505 | ivtv_get_fmt(itv, streamtype, fmt); | ||
506 | if (itv->output_mode != OUT_UDMA_YUV) { | ||
507 | /* TODO: would setting the rect also be valid for this mode? */ | ||
508 | fmt->fmt.pix.top = r.top; | ||
509 | fmt->fmt.pix.left = r.left; | ||
510 | fmt->fmt.pix.width = r.width; | ||
511 | fmt->fmt.pix.height = r.height; | ||
512 | } | ||
513 | if (itv->output_mode == OUT_UDMA_YUV) { | ||
514 | /* TODO: add checks for validity */ | ||
515 | fmt->fmt.pix.field = field; | ||
516 | } | ||
517 | if (set_fmt) { | ||
518 | if (itv->output_mode == OUT_UDMA_YUV) { | ||
519 | switch (field) { | ||
520 | case V4L2_FIELD_NONE: | ||
521 | itv->yuv_info.lace_mode = IVTV_YUV_MODE_PROGRESSIVE; | ||
522 | break; | ||
523 | case V4L2_FIELD_ANY: | ||
524 | itv->yuv_info.lace_mode = IVTV_YUV_MODE_AUTO; | ||
525 | break; | ||
526 | case V4L2_FIELD_INTERLACED_BT: | ||
527 | itv->yuv_info.lace_mode = | ||
528 | IVTV_YUV_MODE_INTERLACED|IVTV_YUV_SYNC_ODD; | ||
529 | break; | ||
530 | case V4L2_FIELD_INTERLACED_TB: | ||
531 | default: | ||
532 | itv->yuv_info.lace_mode = IVTV_YUV_MODE_INTERLACED; | ||
533 | break; | ||
534 | } | ||
535 | itv->yuv_info.lace_sync_field = (itv->yuv_info.lace_mode & IVTV_YUV_SYNC_MASK) == IVTV_YUV_SYNC_EVEN ? 0 : 1; | ||
536 | |||
537 | /* Force update of yuv registers */ | ||
538 | itv->yuv_info.yuv_forced_update = 1; | ||
539 | return 0; | ||
540 | } | ||
541 | if (!ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4, | ||
542 | r.width, r.height, r.left, r.top)) | ||
543 | itv->main_rect = r; | ||
544 | else | ||
545 | return -EINVAL; | ||
546 | } | ||
547 | return 0; | ||
548 | } | ||
549 | |||
550 | if (fmt->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY) { | ||
551 | if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) | ||
552 | return -EINVAL; | ||
553 | if (set_fmt) { | ||
554 | itv->osd_color_key = fmt->fmt.win.chromakey; | ||
555 | itv->osd_global_alpha = fmt->fmt.win.global_alpha; | ||
556 | ivtv_set_osd_alpha(itv); | ||
557 | } | ||
558 | return 0; | ||
559 | } | ||
560 | |||
561 | /* set window size */ | ||
562 | if (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { | ||
563 | int w = fmt->fmt.pix.width; | ||
564 | int h = fmt->fmt.pix.height; | ||
565 | |||
566 | if (w > 720) w = 720; | ||
567 | else if (w < 1) w = 1; | ||
568 | if (h > (itv->is_50hz ? 576 : 480)) h = (itv->is_50hz ? 576 : 480); | ||
569 | else if (h < 2) h = 2; | ||
570 | ivtv_get_fmt(itv, streamtype, fmt); | ||
571 | fmt->fmt.pix.width = w; | ||
572 | fmt->fmt.pix.height = h; | ||
573 | |||
574 | if (!set_fmt || (itv->params.width == w && itv->params.height == h)) | ||
575 | return 0; | ||
576 | if (atomic_read(&itv->capturing) > 0) | ||
577 | return -EBUSY; | ||
578 | |||
579 | itv->params.width = w; | ||
580 | itv->params.height = h; | ||
581 | if (w != 720 || h != (itv->is_50hz ? 576 : 480)) | ||
582 | itv->params.video_temporal_filter = 0; | ||
583 | else | ||
584 | itv->params.video_temporal_filter = 8; | ||
585 | itv->video_dec_func(itv, VIDIOC_S_FMT, fmt); | ||
586 | return ivtv_get_fmt(itv, streamtype, fmt); | ||
587 | } | ||
588 | |||
589 | /* set raw VBI format */ | ||
590 | if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) { | ||
591 | if (set_fmt && streamtype == IVTV_ENC_STREAM_TYPE_VBI && | ||
592 | itv->vbi.sliced_in->service_set && | ||
593 | atomic_read(&itv->capturing) > 0) { | ||
594 | return -EBUSY; | ||
595 | } | ||
596 | if (set_fmt) { | ||
597 | itv->vbi.sliced_in->service_set = 0; | ||
598 | itv->video_dec_func(itv, VIDIOC_S_FMT, &itv->vbi.in); | ||
599 | } | ||
600 | return ivtv_get_fmt(itv, streamtype, fmt); | ||
601 | } | ||
602 | |||
603 | /* set sliced VBI output | ||
604 | In principle the user could request that only certain | ||
605 | VBI types are output and that the others are ignored. | ||
606 | I.e., suppress CC in the even fields or only output | ||
607 | WSS and no VPS. Currently though there is no choice. */ | ||
608 | if (fmt->type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) | ||
609 | return ivtv_get_fmt(itv, streamtype, fmt); | ||
610 | |||
611 | /* any else but sliced VBI capture is an error */ | ||
612 | if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) | ||
613 | return -EINVAL; | ||
614 | |||
615 | if (streamtype == IVTV_DEC_STREAM_TYPE_VBI) | ||
616 | return ivtv_get_fmt(itv, streamtype, fmt); | ||
617 | |||
618 | /* set sliced VBI capture format */ | ||
619 | vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; | ||
620 | memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved)); | ||
621 | |||
622 | if (vbifmt->service_set) | ||
623 | expand_service_set(vbifmt, itv->is_50hz); | ||
624 | set = check_service_set(vbifmt, itv->is_50hz); | ||
625 | vbifmt->service_set = get_service_set(vbifmt); | ||
626 | |||
627 | if (!set_fmt) | ||
628 | return 0; | ||
629 | if (set == 0) | ||
630 | return -EINVAL; | ||
631 | if (atomic_read(&itv->capturing) > 0 && itv->vbi.sliced_in->service_set == 0) { | ||
632 | return -EBUSY; | ||
633 | } | ||
634 | itv->video_dec_func(itv, VIDIOC_S_FMT, fmt); | ||
635 | memcpy(itv->vbi.sliced_in, vbifmt, sizeof(*itv->vbi.sliced_in)); | ||
636 | return 0; | ||
637 | } | ||
638 | |||
639 | static int ivtv_debug_ioctls(struct file *filp, unsigned int cmd, void *arg) | ||
640 | { | ||
641 | struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data; | ||
642 | struct ivtv *itv = id->itv; | ||
643 | struct v4l2_register *reg = arg; | ||
644 | |||
645 | switch (cmd) { | ||
646 | /* ioctls to allow direct access to the encoder registers for testing */ | ||
647 | case VIDIOC_DBG_G_REGISTER: | ||
648 | if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) | ||
649 | return ivtv_itvc(itv, cmd, arg); | ||
650 | if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER) | ||
651 | return ivtv_i2c_id(itv, reg->match_chip, cmd, arg); | ||
652 | return ivtv_call_i2c_client(itv, reg->match_chip, cmd, arg); | ||
653 | |||
654 | case VIDIOC_DBG_S_REGISTER: | ||
655 | if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) | ||
656 | return ivtv_itvc(itv, cmd, arg); | ||
657 | if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER) | ||
658 | return ivtv_i2c_id(itv, reg->match_chip, cmd, arg); | ||
659 | return ivtv_call_i2c_client(itv, reg->match_chip, cmd, arg); | ||
660 | |||
661 | case VIDIOC_G_CHIP_IDENT: { | ||
662 | struct v4l2_chip_ident *chip = arg; | ||
663 | |||
664 | chip->ident = V4L2_IDENT_NONE; | ||
665 | chip->revision = 0; | ||
666 | if (reg->match_type == V4L2_CHIP_MATCH_HOST) { | ||
667 | if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) { | ||
668 | struct v4l2_chip_ident *chip = arg; | ||
669 | |||
670 | chip->ident = itv->has_cx23415 ? V4L2_IDENT_CX23415 : V4L2_IDENT_CX23416; | ||
671 | } | ||
672 | return 0; | ||
673 | } | ||
674 | if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER) | ||
675 | return ivtv_i2c_id(itv, reg->match_chip, cmd, arg); | ||
676 | if (reg->match_type == V4L2_CHIP_MATCH_I2C_ADDR) | ||
677 | return ivtv_call_i2c_client(itv, reg->match_chip, cmd, arg); | ||
678 | return -EINVAL; | ||
679 | } | ||
680 | |||
681 | case VIDIOC_INT_S_AUDIO_ROUTING: { | ||
682 | struct v4l2_routing *route = arg; | ||
683 | |||
684 | ivtv_audio_set_route(itv, route); | ||
685 | break; | ||
686 | } | ||
687 | |||
688 | case VIDIOC_INT_RESET: | ||
689 | ivtv_reset_ir_gpio(itv); | ||
690 | break; | ||
691 | |||
692 | default: | ||
693 | return -EINVAL; | ||
694 | } | ||
695 | return 0; | ||
696 | } | ||
697 | |||
698 | int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void *arg) | ||
699 | { | ||
700 | struct ivtv_open_id *id = NULL; | ||
701 | |||
702 | if (filp) id = (struct ivtv_open_id *)filp->private_data; | ||
703 | |||
704 | switch (cmd) { | ||
705 | case VIDIOC_G_PRIORITY: | ||
706 | { | ||
707 | enum v4l2_priority *p = arg; | ||
708 | |||
709 | *p = v4l2_prio_max(&itv->prio); | ||
710 | break; | ||
711 | } | ||
712 | |||
713 | case VIDIOC_S_PRIORITY: | ||
714 | { | ||
715 | enum v4l2_priority *prio = arg; | ||
716 | |||
717 | return v4l2_prio_change(&itv->prio, &id->prio, *prio); | ||
718 | } | ||
719 | |||
720 | case VIDIOC_QUERYCAP:{ | ||
721 | struct v4l2_capability *vcap = arg; | ||
722 | |||
723 | memset(vcap, 0, sizeof(*vcap)); | ||
724 | strcpy(vcap->driver, IVTV_DRIVER_NAME); /* driver name */ | ||
725 | strcpy(vcap->card, itv->card_name); /* card type */ | ||
726 | strcpy(vcap->bus_info, pci_name(itv->dev)); /* bus info... */ | ||
727 | vcap->version = IVTV_DRIVER_VERSION; /* version */ | ||
728 | vcap->capabilities = itv->v4l2_cap; /* capabilities */ | ||
729 | |||
730 | /* reserved.. must set to 0! */ | ||
731 | vcap->reserved[0] = vcap->reserved[1] = | ||
732 | vcap->reserved[2] = vcap->reserved[3] = 0; | ||
733 | break; | ||
734 | } | ||
735 | |||
736 | case VIDIOC_ENUMAUDIO:{ | ||
737 | struct v4l2_audio *vin = arg; | ||
738 | |||
739 | return ivtv_get_audio_input(itv, vin->index, vin); | ||
740 | } | ||
741 | |||
742 | case VIDIOC_G_AUDIO:{ | ||
743 | struct v4l2_audio *vin = arg; | ||
744 | |||
745 | vin->index = itv->audio_input; | ||
746 | return ivtv_get_audio_input(itv, vin->index, vin); | ||
747 | } | ||
748 | |||
749 | case VIDIOC_S_AUDIO:{ | ||
750 | struct v4l2_audio *vout = arg; | ||
751 | |||
752 | if (vout->index >= itv->nof_audio_inputs) | ||
753 | return -EINVAL; | ||
754 | itv->audio_input = vout->index; | ||
755 | ivtv_audio_set_io(itv); | ||
756 | break; | ||
757 | } | ||
758 | |||
759 | case VIDIOC_ENUMAUDOUT:{ | ||
760 | struct v4l2_audioout *vin = arg; | ||
761 | |||
762 | /* set it to defaults from our table */ | ||
763 | return ivtv_get_audio_output(itv, vin->index, vin); | ||
764 | } | ||
765 | |||
766 | case VIDIOC_G_AUDOUT:{ | ||
767 | struct v4l2_audioout *vin = arg; | ||
768 | |||
769 | vin->index = 0; | ||
770 | return ivtv_get_audio_output(itv, vin->index, vin); | ||
771 | } | ||
772 | |||
773 | case VIDIOC_S_AUDOUT:{ | ||
774 | struct v4l2_audioout *vout = arg; | ||
775 | |||
776 | return ivtv_get_audio_output(itv, vout->index, vout); | ||
777 | } | ||
778 | |||
779 | case VIDIOC_ENUMINPUT:{ | ||
780 | struct v4l2_input *vin = arg; | ||
781 | |||
782 | /* set it to defaults from our table */ | ||
783 | return ivtv_get_input(itv, vin->index, vin); | ||
784 | } | ||
785 | |||
786 | case VIDIOC_ENUMOUTPUT:{ | ||
787 | struct v4l2_output *vout = arg; | ||
788 | |||
789 | return ivtv_get_output(itv, vout->index, vout); | ||
790 | } | ||
791 | |||
792 | case VIDIOC_TRY_FMT: | ||
793 | case VIDIOC_S_FMT: { | ||
794 | struct v4l2_format *fmt = arg; | ||
795 | |||
796 | return ivtv_try_or_set_fmt(itv, id->type, fmt, cmd == VIDIOC_S_FMT); | ||
797 | } | ||
798 | |||
799 | case VIDIOC_G_FMT: { | ||
800 | struct v4l2_format *fmt = arg; | ||
801 | int type = fmt->type; | ||
802 | |||
803 | memset(fmt, 0, sizeof(*fmt)); | ||
804 | fmt->type = type; | ||
805 | return ivtv_get_fmt(itv, id->type, fmt); | ||
806 | } | ||
807 | |||
808 | case VIDIOC_S_CROP: { | ||
809 | struct v4l2_crop *crop = arg; | ||
810 | |||
811 | if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
812 | return -EINVAL; | ||
813 | return itv->video_dec_func(itv, VIDIOC_S_CROP, arg); | ||
814 | } | ||
815 | |||
816 | case VIDIOC_G_CROP: { | ||
817 | struct v4l2_crop *crop = arg; | ||
818 | |||
819 | if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
820 | return -EINVAL; | ||
821 | return itv->video_dec_func(itv, VIDIOC_G_CROP, arg); | ||
822 | } | ||
823 | |||
824 | case VIDIOC_ENUM_FMT: { | ||
825 | static struct v4l2_fmtdesc formats[] = { | ||
826 | { 0, 0, 0, | ||
827 | "HM12 (YUV 4:1:1)", V4L2_PIX_FMT_HM12, | ||
828 | { 0, 0, 0, 0 } | ||
829 | }, | ||
830 | { 1, 0, V4L2_FMT_FLAG_COMPRESSED, | ||
831 | "MPEG", V4L2_PIX_FMT_MPEG, | ||
832 | { 0, 0, 0, 0 } | ||
833 | } | ||
834 | }; | ||
835 | struct v4l2_fmtdesc *fmt = arg; | ||
836 | enum v4l2_buf_type type = fmt->type; | ||
837 | |||
838 | switch (type) { | ||
839 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | ||
840 | break; | ||
841 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: | ||
842 | if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) | ||
843 | return -EINVAL; | ||
844 | break; | ||
845 | default: | ||
846 | return -EINVAL; | ||
847 | } | ||
848 | if (fmt->index > 1) | ||
849 | return -EINVAL; | ||
850 | *fmt = formats[fmt->index]; | ||
851 | fmt->type = type; | ||
852 | return 0; | ||
853 | } | ||
854 | |||
855 | case VIDIOC_G_INPUT:{ | ||
856 | *(int *)arg = itv->active_input; | ||
857 | break; | ||
858 | } | ||
859 | |||
860 | case VIDIOC_S_INPUT:{ | ||
861 | int inp = *(int *)arg; | ||
862 | |||
863 | if (inp < 0 || inp >= itv->nof_inputs) | ||
864 | return -EINVAL; | ||
865 | |||
866 | if (inp == itv->active_input) { | ||
867 | IVTV_DEBUG_INFO("Input unchanged\n"); | ||
868 | break; | ||
869 | } | ||
870 | IVTV_DEBUG_INFO("Changing input from %d to %d\n", | ||
871 | itv->active_input, inp); | ||
872 | |||
873 | itv->active_input = inp; | ||
874 | /* Set the audio input to whatever is appropriate for the | ||
875 | input type. */ | ||
876 | itv->audio_input = itv->card->video_inputs[inp].audio_index; | ||
877 | |||
878 | /* prevent others from messing with the streams until | ||
879 | we're finished changing inputs. */ | ||
880 | ivtv_mute(itv); | ||
881 | ivtv_video_set_io(itv); | ||
882 | ivtv_audio_set_io(itv); | ||
883 | ivtv_unmute(itv); | ||
884 | break; | ||
885 | } | ||
886 | |||
887 | case VIDIOC_G_OUTPUT:{ | ||
888 | if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) | ||
889 | return -EINVAL; | ||
890 | *(int *)arg = itv->active_output; | ||
891 | break; | ||
892 | } | ||
893 | |||
894 | case VIDIOC_S_OUTPUT:{ | ||
895 | int outp = *(int *)arg; | ||
896 | struct v4l2_routing route; | ||
897 | |||
898 | if (outp >= itv->card->nof_outputs) | ||
899 | return -EINVAL; | ||
900 | |||
901 | if (outp == itv->active_output) { | ||
902 | IVTV_DEBUG_INFO("Output unchanged\n"); | ||
903 | break; | ||
904 | } | ||
905 | IVTV_DEBUG_INFO("Changing output from %d to %d\n", | ||
906 | itv->active_output, outp); | ||
907 | |||
908 | itv->active_output = outp; | ||
909 | route.input = SAA7127_INPUT_TYPE_NORMAL; | ||
910 | route.output = itv->card->video_outputs[outp].video_output; | ||
911 | ivtv_saa7127(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route); | ||
912 | break; | ||
913 | } | ||
914 | |||
915 | case VIDIOC_G_FREQUENCY:{ | ||
916 | struct v4l2_frequency *vf = arg; | ||
917 | |||
918 | if (vf->tuner != 0) | ||
919 | return -EINVAL; | ||
920 | ivtv_call_i2c_clients(itv, cmd, arg); | ||
921 | break; | ||
922 | } | ||
923 | |||
924 | case VIDIOC_S_FREQUENCY:{ | ||
925 | struct v4l2_frequency vf = *(struct v4l2_frequency *)arg; | ||
926 | |||
927 | if (vf.tuner != 0) | ||
928 | return -EINVAL; | ||
929 | |||
930 | ivtv_mute(itv); | ||
931 | IVTV_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf.frequency); | ||
932 | ivtv_call_i2c_clients(itv, cmd, &vf); | ||
933 | ivtv_unmute(itv); | ||
934 | break; | ||
935 | } | ||
936 | |||
937 | case VIDIOC_ENUMSTD:{ | ||
938 | struct v4l2_standard *vs = arg; | ||
939 | int idx = vs->index; | ||
940 | |||
941 | if (idx < 0 || idx >= ARRAY_SIZE(enum_stds)) | ||
942 | return -EINVAL; | ||
943 | |||
944 | *vs = (enum_stds[idx].std & V4L2_STD_525_60) ? | ||
945 | ivtv_std_60hz : ivtv_std_50hz; | ||
946 | vs->index = idx; | ||
947 | vs->id = enum_stds[idx].std; | ||
948 | strcpy(vs->name, enum_stds[idx].name); | ||
949 | break; | ||
950 | } | ||
951 | |||
952 | case VIDIOC_G_STD:{ | ||
953 | *(v4l2_std_id *) arg = itv->std; | ||
954 | break; | ||
955 | } | ||
956 | |||
957 | case VIDIOC_S_STD: { | ||
958 | v4l2_std_id std = *(v4l2_std_id *) arg; | ||
959 | |||
960 | if ((std & V4L2_STD_ALL) == 0) | ||
961 | return -EINVAL; | ||
962 | |||
963 | if (std == itv->std) | ||
964 | break; | ||
965 | |||
966 | if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) || | ||
967 | atomic_read(&itv->capturing) > 0 || | ||
968 | atomic_read(&itv->decoding) > 0) { | ||
969 | /* Switching standard would turn off the radio or mess | ||
970 | with already running streams, prevent that by | ||
971 | returning EBUSY. */ | ||
972 | return -EBUSY; | ||
973 | } | ||
974 | |||
975 | itv->std = std; | ||
976 | itv->is_60hz = (std & V4L2_STD_525_60) ? 1 : 0; | ||
977 | itv->params.is_50hz = itv->is_50hz = !itv->is_60hz; | ||
978 | itv->params.width = 720; | ||
979 | itv->params.height = itv->is_50hz ? 576 : 480; | ||
980 | itv->vbi.count = itv->is_50hz ? 18 : 12; | ||
981 | itv->vbi.start[0] = itv->is_50hz ? 6 : 10; | ||
982 | itv->vbi.start[1] = itv->is_50hz ? 318 : 273; | ||
983 | if (itv->hw_flags & IVTV_HW_CX25840) { | ||
984 | itv->vbi.sliced_decoder_line_size = itv->is_60hz ? 272 : 284; | ||
985 | } | ||
986 | IVTV_DEBUG_INFO("Switching standard to %llx.\n", itv->std); | ||
987 | |||
988 | /* Tuner */ | ||
989 | ivtv_call_i2c_clients(itv, VIDIOC_S_STD, &itv->std); | ||
990 | |||
991 | if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) { | ||
992 | /* set display standard */ | ||
993 | itv->std_out = std; | ||
994 | itv->is_out_60hz = itv->is_60hz; | ||
995 | itv->is_out_50hz = itv->is_50hz; | ||
996 | ivtv_call_i2c_clients(itv, VIDIOC_INT_S_STD_OUTPUT, &itv->std_out); | ||
997 | ivtv_vapi(itv, CX2341X_DEC_SET_STANDARD, 1, itv->is_out_50hz); | ||
998 | itv->main_rect.left = itv->main_rect.top = 0; | ||
999 | itv->main_rect.width = 720; | ||
1000 | itv->main_rect.height = itv->params.height; | ||
1001 | ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4, | ||
1002 | 720, itv->main_rect.height, 0, 0); | ||
1003 | } | ||
1004 | break; | ||
1005 | } | ||
1006 | |||
1007 | case VIDIOC_S_TUNER: { /* Setting tuner can only set audio mode */ | ||
1008 | struct v4l2_tuner *vt = arg; | ||
1009 | |||
1010 | if (vt->index != 0) | ||
1011 | return -EINVAL; | ||
1012 | |||
1013 | ivtv_call_i2c_clients(itv, VIDIOC_S_TUNER, vt); | ||
1014 | break; | ||
1015 | } | ||
1016 | |||
1017 | case VIDIOC_G_TUNER: { | ||
1018 | struct v4l2_tuner *vt = arg; | ||
1019 | |||
1020 | if (vt->index != 0) | ||
1021 | return -EINVAL; | ||
1022 | |||
1023 | memset(vt, 0, sizeof(*vt)); | ||
1024 | ivtv_call_i2c_clients(itv, VIDIOC_G_TUNER, vt); | ||
1025 | |||
1026 | if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) { | ||
1027 | strcpy(vt->name, "ivtv Radio Tuner"); | ||
1028 | vt->type = V4L2_TUNER_RADIO; | ||
1029 | } else { | ||
1030 | strcpy(vt->name, "ivtv TV Tuner"); | ||
1031 | vt->type = V4L2_TUNER_ANALOG_TV; | ||
1032 | } | ||
1033 | break; | ||
1034 | } | ||
1035 | |||
1036 | case VIDIOC_G_SLICED_VBI_CAP: { | ||
1037 | struct v4l2_sliced_vbi_cap *cap = arg; | ||
1038 | int set = itv->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525; | ||
1039 | int f, l; | ||
1040 | enum v4l2_buf_type type = cap->type; | ||
1041 | |||
1042 | memset(cap, 0, sizeof(*cap)); | ||
1043 | cap->type = type; | ||
1044 | if (type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) { | ||
1045 | for (f = 0; f < 2; f++) { | ||
1046 | for (l = 0; l < 24; l++) { | ||
1047 | if (valid_service_line(f, l, itv->is_50hz)) { | ||
1048 | cap->service_lines[f][l] = set; | ||
1049 | } | ||
1050 | } | ||
1051 | } | ||
1052 | return 0; | ||
1053 | } | ||
1054 | if (type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) { | ||
1055 | if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_OUTPUT)) | ||
1056 | return -EINVAL; | ||
1057 | if (itv->is_60hz) { | ||
1058 | cap->service_lines[0][21] = V4L2_SLICED_CAPTION_525; | ||
1059 | cap->service_lines[1][21] = V4L2_SLICED_CAPTION_525; | ||
1060 | } else { | ||
1061 | cap->service_lines[0][23] = V4L2_SLICED_WSS_625; | ||
1062 | cap->service_lines[0][16] = V4L2_SLICED_VPS; | ||
1063 | } | ||
1064 | return 0; | ||
1065 | } | ||
1066 | return -EINVAL; | ||
1067 | } | ||
1068 | |||
1069 | case VIDIOC_G_ENC_INDEX: { | ||
1070 | struct v4l2_enc_idx *idx = arg; | ||
1071 | int i; | ||
1072 | |||
1073 | idx->entries = (itv->pgm_info_write_idx + IVTV_MAX_PGM_INDEX - itv->pgm_info_read_idx) % | ||
1074 | IVTV_MAX_PGM_INDEX; | ||
1075 | if (idx->entries > V4L2_ENC_IDX_ENTRIES) | ||
1076 | idx->entries = V4L2_ENC_IDX_ENTRIES; | ||
1077 | for (i = 0; i < idx->entries; i++) { | ||
1078 | idx->entry[i] = itv->pgm_info[(itv->pgm_info_read_idx + i) % IVTV_MAX_PGM_INDEX]; | ||
1079 | } | ||
1080 | itv->pgm_info_read_idx = (itv->pgm_info_read_idx + idx->entries) % IVTV_MAX_PGM_INDEX; | ||
1081 | break; | ||
1082 | } | ||
1083 | |||
1084 | case VIDIOC_ENCODER_CMD: | ||
1085 | case VIDIOC_TRY_ENCODER_CMD: { | ||
1086 | struct v4l2_encoder_cmd *enc = arg; | ||
1087 | int try = cmd == VIDIOC_TRY_ENCODER_CMD; | ||
1088 | |||
1089 | memset(&enc->raw, 0, sizeof(enc->raw)); | ||
1090 | switch (enc->cmd) { | ||
1091 | case V4L2_ENC_CMD_START: | ||
1092 | enc->flags = 0; | ||
1093 | if (try) | ||
1094 | return 0; | ||
1095 | return ivtv_start_capture(id); | ||
1096 | |||
1097 | case V4L2_ENC_CMD_STOP: | ||
1098 | enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END; | ||
1099 | if (try) | ||
1100 | return 0; | ||
1101 | ivtv_stop_capture(id, enc->flags & V4L2_ENC_CMD_STOP_AT_GOP_END); | ||
1102 | return 0; | ||
1103 | |||
1104 | case V4L2_ENC_CMD_PAUSE: | ||
1105 | enc->flags = 0; | ||
1106 | if (try) | ||
1107 | return 0; | ||
1108 | if (!atomic_read(&itv->capturing)) | ||
1109 | return -EPERM; | ||
1110 | if (test_and_set_bit(IVTV_F_I_ENC_PAUSED, &itv->i_flags)) | ||
1111 | return 0; | ||
1112 | ivtv_mute(itv); | ||
1113 | ivtv_vapi(itv, CX2341X_ENC_PAUSE_ENCODER, 1, 0); | ||
1114 | break; | ||
1115 | |||
1116 | case V4L2_ENC_CMD_RESUME: | ||
1117 | enc->flags = 0; | ||
1118 | if (try) | ||
1119 | return 0; | ||
1120 | if (!atomic_read(&itv->capturing)) | ||
1121 | return -EPERM; | ||
1122 | if (!test_and_clear_bit(IVTV_F_I_ENC_PAUSED, &itv->i_flags)) | ||
1123 | return 0; | ||
1124 | ivtv_vapi(itv, CX2341X_ENC_PAUSE_ENCODER, 1, 1); | ||
1125 | ivtv_unmute(itv); | ||
1126 | break; | ||
1127 | default: | ||
1128 | return -EINVAL; | ||
1129 | } | ||
1130 | break; | ||
1131 | } | ||
1132 | |||
1133 | case VIDIOC_G_FBUF: { | ||
1134 | struct v4l2_framebuffer *fb = arg; | ||
1135 | |||
1136 | memset(fb, 0, sizeof(*fb)); | ||
1137 | if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) | ||
1138 | break; | ||
1139 | fb->capability = V4L2_FBUF_CAP_EXTERNOVERLAY | V4L2_FBUF_CAP_CHROMAKEY | | ||
1140 | V4L2_FBUF_CAP_LOCAL_ALPHA | V4L2_FBUF_CAP_GLOBAL_ALPHA; | ||
1141 | fb->fmt.pixelformat = itv->osd_pixelformat; | ||
1142 | fb->fmt.width = itv->osd_rect.width; | ||
1143 | fb->fmt.height = itv->osd_rect.height; | ||
1144 | fb->fmt.left = itv->osd_rect.left; | ||
1145 | fb->fmt.top = itv->osd_rect.top; | ||
1146 | fb->base = (void *)itv->osd_video_pbase; | ||
1147 | if (itv->osd_global_alpha_state) | ||
1148 | fb->flags |= V4L2_FBUF_FLAG_GLOBAL_ALPHA; | ||
1149 | if (itv->osd_local_alpha_state) | ||
1150 | fb->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA; | ||
1151 | if (itv->osd_color_key_state) | ||
1152 | fb->flags |= V4L2_FBUF_FLAG_CHROMAKEY; | ||
1153 | break; | ||
1154 | } | ||
1155 | |||
1156 | case VIDIOC_S_FBUF: { | ||
1157 | struct v4l2_framebuffer *fb = arg; | ||
1158 | |||
1159 | if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) | ||
1160 | break; | ||
1161 | itv->osd_global_alpha_state = (fb->flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) != 0; | ||
1162 | itv->osd_local_alpha_state = (fb->flags & V4L2_FBUF_FLAG_LOCAL_ALPHA) != 0; | ||
1163 | itv->osd_color_key_state = (fb->flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0; | ||
1164 | break; | ||
1165 | } | ||
1166 | |||
1167 | case VIDIOC_LOG_STATUS: | ||
1168 | { | ||
1169 | int has_output = itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT; | ||
1170 | struct v4l2_input vidin; | ||
1171 | struct v4l2_audio audin; | ||
1172 | int i; | ||
1173 | |||
1174 | IVTV_INFO("================= START STATUS CARD #%d =================\n", itv->num); | ||
1175 | if (itv->hw_flags & IVTV_HW_TVEEPROM) { | ||
1176 | struct tveeprom tv; | ||
1177 | |||
1178 | ivtv_read_eeprom(itv, &tv); | ||
1179 | } | ||
1180 | ivtv_call_i2c_clients(itv, VIDIOC_LOG_STATUS, NULL); | ||
1181 | ivtv_get_input(itv, itv->active_input, &vidin); | ||
1182 | ivtv_get_audio_input(itv, itv->audio_input, &audin); | ||
1183 | IVTV_INFO("Video Input: %s\n", vidin.name); | ||
1184 | IVTV_INFO("Audio Input: %s\n", audin.name); | ||
1185 | if (has_output) { | ||
1186 | struct v4l2_output vidout; | ||
1187 | struct v4l2_audioout audout; | ||
1188 | int mode = itv->output_mode; | ||
1189 | static const char * const output_modes[] = { | ||
1190 | "None", | ||
1191 | "MPEG Streaming", | ||
1192 | "YUV Streaming", | ||
1193 | "YUV Frames", | ||
1194 | "Passthrough", | ||
1195 | }; | ||
1196 | |||
1197 | ivtv_get_output(itv, itv->active_output, &vidout); | ||
1198 | ivtv_get_audio_output(itv, 0, &audout); | ||
1199 | IVTV_INFO("Video Output: %s\n", vidout.name); | ||
1200 | IVTV_INFO("Audio Output: %s\n", audout.name); | ||
1201 | if (mode < 0 || mode > OUT_PASSTHROUGH) | ||
1202 | mode = OUT_NONE; | ||
1203 | IVTV_INFO("Output Mode: %s\n", output_modes[mode]); | ||
1204 | } | ||
1205 | IVTV_INFO("Tuner: %s\n", | ||
1206 | test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ? "Radio" : "TV"); | ||
1207 | cx2341x_log_status(&itv->params, itv->name); | ||
1208 | IVTV_INFO("Status flags: 0x%08lx\n", itv->i_flags); | ||
1209 | for (i = 0; i < IVTV_MAX_STREAMS; i++) { | ||
1210 | struct ivtv_stream *s = &itv->streams[i]; | ||
1211 | |||
1212 | if (s->v4l2dev == NULL || s->buffers == 0) | ||
1213 | continue; | ||
1214 | IVTV_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n", s->name, s->s_flags, | ||
1215 | (s->buffers - s->q_free.buffers) * 100 / s->buffers, | ||
1216 | (s->buffers * s->buf_size) / 1024, s->buffers); | ||
1217 | } | ||
1218 | IVTV_INFO("Read MPEG/VBI: %lld/%lld bytes\n", itv->mpg_data_received, itv->vbi_data_inserted); | ||
1219 | IVTV_INFO("================== END STATUS CARD #%d ==================\n", itv->num); | ||
1220 | break; | ||
1221 | } | ||
1222 | |||
1223 | default: | ||
1224 | return -EINVAL; | ||
1225 | } | ||
1226 | return 0; | ||
1227 | } | ||
1228 | |||
1229 | static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg) | ||
1230 | { | ||
1231 | struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data; | ||
1232 | struct ivtv *itv = id->itv; | ||
1233 | int nonblocking = filp->f_flags & O_NONBLOCK; | ||
1234 | struct ivtv_stream *s = &itv->streams[id->type]; | ||
1235 | |||
1236 | switch (cmd) { | ||
1237 | case IVTV_IOC_DMA_FRAME: { | ||
1238 | struct ivtv_dma_frame *args = arg; | ||
1239 | |||
1240 | IVTV_DEBUG_IOCTL("IVTV_IOC_DMA_FRAME\n"); | ||
1241 | if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) | ||
1242 | return -EINVAL; | ||
1243 | if (args->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) | ||
1244 | return -EINVAL; | ||
1245 | if (itv->output_mode == OUT_UDMA_YUV && args->y_source == NULL) | ||
1246 | return 0; | ||
1247 | if (ivtv_claim_stream(id, id->type)) { | ||
1248 | return -EBUSY; | ||
1249 | } | ||
1250 | if (ivtv_set_output_mode(itv, OUT_UDMA_YUV) != OUT_UDMA_YUV) { | ||
1251 | ivtv_release_stream(s); | ||
1252 | return -EBUSY; | ||
1253 | } | ||
1254 | if (args->y_source == NULL) | ||
1255 | return 0; | ||
1256 | return ivtv_yuv_prep_frame(itv, args); | ||
1257 | } | ||
1258 | |||
1259 | case VIDEO_GET_PTS: { | ||
1260 | u32 data[CX2341X_MBOX_MAX_DATA]; | ||
1261 | u64 *pts = arg; | ||
1262 | |||
1263 | IVTV_DEBUG_IOCTL("VIDEO_GET_PTS\n"); | ||
1264 | if (s->type < IVTV_DEC_STREAM_TYPE_MPG) { | ||
1265 | *pts = s->dma_pts; | ||
1266 | break; | ||
1267 | } | ||
1268 | if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) | ||
1269 | return -EINVAL; | ||
1270 | |||
1271 | if (test_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags)) { | ||
1272 | *pts = (u64) ((u64)itv->last_dec_timing[2] << 32) | | ||
1273 | (u64)itv->last_dec_timing[1]; | ||
1274 | break; | ||
1275 | } | ||
1276 | *pts = 0; | ||
1277 | if (atomic_read(&itv->decoding)) { | ||
1278 | if (ivtv_api(itv, CX2341X_DEC_GET_TIMING_INFO, 5, data)) { | ||
1279 | IVTV_DEBUG_WARN("GET_TIMING: couldn't read clock\n"); | ||
1280 | return -EIO; | ||
1281 | } | ||
1282 | memcpy(itv->last_dec_timing, data, sizeof(itv->last_dec_timing)); | ||
1283 | set_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags); | ||
1284 | *pts = (u64) ((u64) data[2] << 32) | (u64) data[1]; | ||
1285 | /*timing->scr = (u64) (((u64) data[4] << 32) | (u64) (data[3]));*/ | ||
1286 | } | ||
1287 | break; | ||
1288 | } | ||
1289 | |||
1290 | case VIDEO_GET_FRAME_COUNT: { | ||
1291 | u32 data[CX2341X_MBOX_MAX_DATA]; | ||
1292 | u64 *frame = arg; | ||
1293 | |||
1294 | IVTV_DEBUG_IOCTL("VIDEO_GET_FRAME_COUNT\n"); | ||
1295 | if (s->type < IVTV_DEC_STREAM_TYPE_MPG) { | ||
1296 | *frame = 0; | ||
1297 | break; | ||
1298 | } | ||
1299 | if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) | ||
1300 | return -EINVAL; | ||
1301 | |||
1302 | if (test_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags)) { | ||
1303 | *frame = itv->last_dec_timing[0]; | ||
1304 | break; | ||
1305 | } | ||
1306 | *frame = 0; | ||
1307 | if (atomic_read(&itv->decoding)) { | ||
1308 | if (ivtv_api(itv, CX2341X_DEC_GET_TIMING_INFO, 5, data)) { | ||
1309 | IVTV_DEBUG_WARN("GET_TIMING: couldn't read clock\n"); | ||
1310 | return -EIO; | ||
1311 | } | ||
1312 | memcpy(itv->last_dec_timing, data, sizeof(itv->last_dec_timing)); | ||
1313 | set_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags); | ||
1314 | *frame = data[0]; | ||
1315 | } | ||
1316 | break; | ||
1317 | } | ||
1318 | |||
1319 | case VIDEO_PLAY: { | ||
1320 | struct video_command vc; | ||
1321 | |||
1322 | IVTV_DEBUG_IOCTL("VIDEO_PLAY\n"); | ||
1323 | memset(&vc, 0, sizeof(vc)); | ||
1324 | vc.cmd = VIDEO_CMD_PLAY; | ||
1325 | return ivtv_video_command(itv, id, &vc, 0); | ||
1326 | } | ||
1327 | |||
1328 | case VIDEO_STOP: { | ||
1329 | struct video_command vc; | ||
1330 | |||
1331 | IVTV_DEBUG_IOCTL("VIDEO_STOP\n"); | ||
1332 | memset(&vc, 0, sizeof(vc)); | ||
1333 | vc.cmd = VIDEO_CMD_STOP; | ||
1334 | vc.flags = VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY; | ||
1335 | return ivtv_video_command(itv, id, &vc, 0); | ||
1336 | } | ||
1337 | |||
1338 | case VIDEO_FREEZE: { | ||
1339 | struct video_command vc; | ||
1340 | |||
1341 | IVTV_DEBUG_IOCTL("VIDEO_FREEZE\n"); | ||
1342 | memset(&vc, 0, sizeof(vc)); | ||
1343 | vc.cmd = VIDEO_CMD_FREEZE; | ||
1344 | return ivtv_video_command(itv, id, &vc, 0); | ||
1345 | } | ||
1346 | |||
1347 | case VIDEO_CONTINUE: { | ||
1348 | struct video_command vc; | ||
1349 | |||
1350 | IVTV_DEBUG_IOCTL("VIDEO_CONTINUE\n"); | ||
1351 | memset(&vc, 0, sizeof(vc)); | ||
1352 | vc.cmd = VIDEO_CMD_CONTINUE; | ||
1353 | return ivtv_video_command(itv, id, &vc, 0); | ||
1354 | } | ||
1355 | |||
1356 | case VIDEO_COMMAND: | ||
1357 | case VIDEO_TRY_COMMAND: { | ||
1358 | struct video_command *vc = arg; | ||
1359 | int try = (cmd == VIDEO_TRY_COMMAND); | ||
1360 | |||
1361 | if (try) | ||
1362 | IVTV_DEBUG_IOCTL("VIDEO_TRY_COMMAND\n"); | ||
1363 | else | ||
1364 | IVTV_DEBUG_IOCTL("VIDEO_COMMAND\n"); | ||
1365 | return ivtv_video_command(itv, id, vc, try); | ||
1366 | } | ||
1367 | |||
1368 | case VIDEO_GET_EVENT: { | ||
1369 | struct video_event *ev = arg; | ||
1370 | DEFINE_WAIT(wait); | ||
1371 | |||
1372 | IVTV_DEBUG_IOCTL("VIDEO_GET_EVENT\n"); | ||
1373 | if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) | ||
1374 | return -EINVAL; | ||
1375 | memset(ev, 0, sizeof(*ev)); | ||
1376 | set_bit(IVTV_F_I_EV_VSYNC_ENABLED, &itv->i_flags); | ||
1377 | |||
1378 | while (1) { | ||
1379 | if (test_and_clear_bit(IVTV_F_I_EV_DEC_STOPPED, &itv->i_flags)) | ||
1380 | ev->type = VIDEO_EVENT_DECODER_STOPPED; | ||
1381 | else if (test_and_clear_bit(IVTV_F_I_EV_VSYNC, &itv->i_flags)) { | ||
1382 | ev->type = VIDEO_EVENT_VSYNC; | ||
1383 | ev->u.vsync_field = test_bit(IVTV_F_I_EV_VSYNC_FIELD, &itv->i_flags) ? | ||
1384 | VIDEO_VSYNC_FIELD_ODD : VIDEO_VSYNC_FIELD_EVEN; | ||
1385 | if (itv->output_mode == OUT_UDMA_YUV && | ||
1386 | (itv->yuv_info.lace_mode & IVTV_YUV_MODE_MASK) == | ||
1387 | IVTV_YUV_MODE_PROGRESSIVE) { | ||
1388 | ev->u.vsync_field = VIDEO_VSYNC_FIELD_PROGRESSIVE; | ||
1389 | } | ||
1390 | } | ||
1391 | if (ev->type) | ||
1392 | return 0; | ||
1393 | if (nonblocking) | ||
1394 | return -EAGAIN; | ||
1395 | /* wait for event */ | ||
1396 | prepare_to_wait(&itv->event_waitq, &wait, TASK_INTERRUPTIBLE); | ||
1397 | if ((itv->i_flags & (IVTV_F_I_EV_DEC_STOPPED|IVTV_F_I_EV_VSYNC)) == 0) | ||
1398 | schedule(); | ||
1399 | finish_wait(&itv->event_waitq, &wait); | ||
1400 | if (signal_pending(current)) { | ||
1401 | /* return if a signal was received */ | ||
1402 | IVTV_DEBUG_INFO("User stopped wait for event\n"); | ||
1403 | return -EINTR; | ||
1404 | } | ||
1405 | } | ||
1406 | break; | ||
1407 | } | ||
1408 | |||
1409 | default: | ||
1410 | return -EINVAL; | ||
1411 | } | ||
1412 | return 0; | ||
1413 | } | ||
1414 | |||
1415 | static int ivtv_v4l2_do_ioctl(struct inode *inode, struct file *filp, | ||
1416 | unsigned int cmd, void *arg) | ||
1417 | { | ||
1418 | struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data; | ||
1419 | struct ivtv *itv = id->itv; | ||
1420 | int ret; | ||
1421 | |||
1422 | /* check priority */ | ||
1423 | switch (cmd) { | ||
1424 | case VIDIOC_S_CTRL: | ||
1425 | case VIDIOC_S_STD: | ||
1426 | case VIDIOC_S_INPUT: | ||
1427 | case VIDIOC_S_OUTPUT: | ||
1428 | case VIDIOC_S_TUNER: | ||
1429 | case VIDIOC_S_FREQUENCY: | ||
1430 | case VIDIOC_S_FMT: | ||
1431 | case VIDIOC_S_CROP: | ||
1432 | case VIDIOC_S_AUDIO: | ||
1433 | case VIDIOC_S_AUDOUT: | ||
1434 | case VIDIOC_S_EXT_CTRLS: | ||
1435 | case VIDIOC_S_FBUF: | ||
1436 | ret = v4l2_prio_check(&itv->prio, &id->prio); | ||
1437 | if (ret) | ||
1438 | return ret; | ||
1439 | } | ||
1440 | |||
1441 | switch (cmd) { | ||
1442 | case VIDIOC_DBG_G_REGISTER: | ||
1443 | case VIDIOC_DBG_S_REGISTER: | ||
1444 | case VIDIOC_G_CHIP_IDENT: | ||
1445 | case VIDIOC_INT_S_AUDIO_ROUTING: | ||
1446 | case VIDIOC_INT_RESET: | ||
1447 | if (ivtv_debug & IVTV_DBGFLG_IOCTL) { | ||
1448 | printk(KERN_INFO "ivtv%d ioctl: ", itv->num); | ||
1449 | v4l_printk_ioctl(cmd); | ||
1450 | } | ||
1451 | return ivtv_debug_ioctls(filp, cmd, arg); | ||
1452 | |||
1453 | case VIDIOC_G_PRIORITY: | ||
1454 | case VIDIOC_S_PRIORITY: | ||
1455 | case VIDIOC_QUERYCAP: | ||
1456 | case VIDIOC_ENUMINPUT: | ||
1457 | case VIDIOC_G_INPUT: | ||
1458 | case VIDIOC_S_INPUT: | ||
1459 | case VIDIOC_ENUMOUTPUT: | ||
1460 | case VIDIOC_G_OUTPUT: | ||
1461 | case VIDIOC_S_OUTPUT: | ||
1462 | case VIDIOC_G_FMT: | ||
1463 | case VIDIOC_S_FMT: | ||
1464 | case VIDIOC_TRY_FMT: | ||
1465 | case VIDIOC_ENUM_FMT: | ||
1466 | case VIDIOC_G_CROP: | ||
1467 | case VIDIOC_S_CROP: | ||
1468 | case VIDIOC_G_FREQUENCY: | ||
1469 | case VIDIOC_S_FREQUENCY: | ||
1470 | case VIDIOC_ENUMSTD: | ||
1471 | case VIDIOC_G_STD: | ||
1472 | case VIDIOC_S_STD: | ||
1473 | case VIDIOC_S_TUNER: | ||
1474 | case VIDIOC_G_TUNER: | ||
1475 | case VIDIOC_ENUMAUDIO: | ||
1476 | case VIDIOC_S_AUDIO: | ||
1477 | case VIDIOC_G_AUDIO: | ||
1478 | case VIDIOC_ENUMAUDOUT: | ||
1479 | case VIDIOC_S_AUDOUT: | ||
1480 | case VIDIOC_G_AUDOUT: | ||
1481 | case VIDIOC_G_SLICED_VBI_CAP: | ||
1482 | case VIDIOC_LOG_STATUS: | ||
1483 | case VIDIOC_G_ENC_INDEX: | ||
1484 | case VIDIOC_ENCODER_CMD: | ||
1485 | case VIDIOC_TRY_ENCODER_CMD: | ||
1486 | case VIDIOC_G_FBUF: | ||
1487 | case VIDIOC_S_FBUF: | ||
1488 | if (ivtv_debug & IVTV_DBGFLG_IOCTL) { | ||
1489 | printk(KERN_INFO "ivtv%d ioctl: ", itv->num); | ||
1490 | v4l_printk_ioctl(cmd); | ||
1491 | } | ||
1492 | return ivtv_v4l2_ioctls(itv, filp, cmd, arg); | ||
1493 | |||
1494 | case VIDIOC_QUERYMENU: | ||
1495 | case VIDIOC_QUERYCTRL: | ||
1496 | case VIDIOC_S_CTRL: | ||
1497 | case VIDIOC_G_CTRL: | ||
1498 | case VIDIOC_S_EXT_CTRLS: | ||
1499 | case VIDIOC_G_EXT_CTRLS: | ||
1500 | case VIDIOC_TRY_EXT_CTRLS: | ||
1501 | if (ivtv_debug & IVTV_DBGFLG_IOCTL) { | ||
1502 | printk(KERN_INFO "ivtv%d ioctl: ", itv->num); | ||
1503 | v4l_printk_ioctl(cmd); | ||
1504 | } | ||
1505 | return ivtv_control_ioctls(itv, cmd, arg); | ||
1506 | |||
1507 | case IVTV_IOC_DMA_FRAME: | ||
1508 | case VIDEO_GET_PTS: | ||
1509 | case VIDEO_GET_FRAME_COUNT: | ||
1510 | case VIDEO_GET_EVENT: | ||
1511 | case VIDEO_PLAY: | ||
1512 | case VIDEO_STOP: | ||
1513 | case VIDEO_FREEZE: | ||
1514 | case VIDEO_CONTINUE: | ||
1515 | case VIDEO_COMMAND: | ||
1516 | case VIDEO_TRY_COMMAND: | ||
1517 | return ivtv_decoder_ioctls(filp, cmd, arg); | ||
1518 | |||
1519 | case 0x00005401: /* Handle isatty() calls */ | ||
1520 | return -EINVAL; | ||
1521 | default: | ||
1522 | return v4l_compat_translate_ioctl(inode, filp, cmd, arg, | ||
1523 | ivtv_v4l2_do_ioctl); | ||
1524 | } | ||
1525 | return 0; | ||
1526 | } | ||
1527 | |||
1528 | int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, | ||
1529 | unsigned long arg) | ||
1530 | { | ||
1531 | struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data; | ||
1532 | struct ivtv *itv = id->itv; | ||
1533 | |||
1534 | /* Filter dvb ioctls that cannot be handled by video_usercopy */ | ||
1535 | switch (cmd) { | ||
1536 | case VIDEO_SELECT_SOURCE: | ||
1537 | IVTV_DEBUG_IOCTL("VIDEO_SELECT_SOURCE\n"); | ||
1538 | if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) | ||
1539 | return -EINVAL; | ||
1540 | return ivtv_passthrough_mode(itv, arg == VIDEO_SOURCE_DEMUX); | ||
1541 | |||
1542 | case AUDIO_SET_MUTE: | ||
1543 | IVTV_DEBUG_IOCTL("AUDIO_SET_MUTE\n"); | ||
1544 | itv->speed_mute_audio = arg; | ||
1545 | return 0; | ||
1546 | |||
1547 | case AUDIO_CHANNEL_SELECT: | ||
1548 | IVTV_DEBUG_IOCTL("AUDIO_CHANNEL_SELECT\n"); | ||
1549 | if (arg > AUDIO_STEREO_SWAPPED) | ||
1550 | return -EINVAL; | ||
1551 | itv->audio_stereo_mode = arg; | ||
1552 | ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode); | ||
1553 | return 0; | ||
1554 | |||
1555 | case AUDIO_BILINGUAL_CHANNEL_SELECT: | ||
1556 | IVTV_DEBUG_IOCTL("AUDIO_BILINGUAL_CHANNEL_SELECT\n"); | ||
1557 | if (arg > AUDIO_STEREO_SWAPPED) | ||
1558 | return -EINVAL; | ||
1559 | itv->audio_bilingual_mode = arg; | ||
1560 | ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode); | ||
1561 | return 0; | ||
1562 | |||
1563 | default: | ||
1564 | break; | ||
1565 | } | ||
1566 | return video_usercopy(inode, filp, cmd, arg, ivtv_v4l2_do_ioctl); | ||
1567 | } | ||
diff --git a/drivers/media/video/ivtv/ivtv-ioctl.h b/drivers/media/video/ivtv/ivtv-ioctl.h new file mode 100644 index 000000000000..cbccf7a9f65c --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-ioctl.h | |||
@@ -0,0 +1,28 @@ | |||
1 | /* | ||
2 | ioctl system call | ||
3 | Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> | ||
4 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | u16 service2vbi(int type); | ||
22 | void expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal); | ||
23 | u16 get_service_set(struct v4l2_sliced_vbi_format *fmt); | ||
24 | int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, | ||
25 | unsigned long arg); | ||
26 | int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void *arg); | ||
27 | void ivtv_set_osd_alpha(struct ivtv *itv); | ||
28 | int ivtv_set_speed(struct ivtv *itv, int speed); | ||
diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c new file mode 100644 index 000000000000..c3a047b381b3 --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-irq.c | |||
@@ -0,0 +1,838 @@ | |||
1 | /* interrupt handling | ||
2 | Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> | ||
3 | Copyright (C) 2004 Chris Kennedy <c@groovy.org> | ||
4 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | #include "ivtv-driver.h" | ||
22 | #include "ivtv-firmware.h" | ||
23 | #include "ivtv-fileops.h" | ||
24 | #include "ivtv-queue.h" | ||
25 | #include "ivtv-udma.h" | ||
26 | #include "ivtv-irq.h" | ||
27 | #include "ivtv-ioctl.h" | ||
28 | #include "ivtv-mailbox.h" | ||
29 | #include "ivtv-vbi.h" | ||
30 | #include "ivtv-yuv.h" | ||
31 | |||
32 | #define DMA_MAGIC_COOKIE 0x000001fe | ||
33 | |||
34 | #define SLICED_VBI_PIO 1 | ||
35 | |||
36 | static void ivtv_dma_dec_start(struct ivtv_stream *s); | ||
37 | |||
38 | static const int ivtv_stream_map[] = { | ||
39 | IVTV_ENC_STREAM_TYPE_MPG, | ||
40 | IVTV_ENC_STREAM_TYPE_YUV, | ||
41 | IVTV_ENC_STREAM_TYPE_PCM, | ||
42 | IVTV_ENC_STREAM_TYPE_VBI, | ||
43 | }; | ||
44 | |||
45 | static inline int ivtv_use_pio(struct ivtv_stream *s) | ||
46 | { | ||
47 | struct ivtv *itv = s->itv; | ||
48 | |||
49 | return s->dma == PCI_DMA_NONE || | ||
50 | (SLICED_VBI_PIO && s->type == IVTV_ENC_STREAM_TYPE_VBI && itv->vbi.sliced_in->service_set); | ||
51 | } | ||
52 | |||
53 | void ivtv_irq_work_handler(struct work_struct *work) | ||
54 | { | ||
55 | struct ivtv *itv = container_of(work, struct ivtv, irq_work_queue); | ||
56 | |||
57 | DEFINE_WAIT(wait); | ||
58 | |||
59 | if (test_and_clear_bit(IVTV_F_I_WORK_HANDLER_VBI, &itv->i_flags)) | ||
60 | vbi_work_handler(itv); | ||
61 | |||
62 | if (test_and_clear_bit(IVTV_F_I_WORK_HANDLER_YUV, &itv->i_flags)) | ||
63 | ivtv_yuv_work_handler(itv); | ||
64 | } | ||
65 | |||
66 | /* Determine the required DMA size, setup enough buffers in the predma queue and | ||
67 | actually copy the data from the card to the buffers in case a PIO transfer is | ||
68 | required for this stream. | ||
69 | */ | ||
70 | static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MAX_DATA]) | ||
71 | { | ||
72 | struct ivtv *itv = s->itv; | ||
73 | struct ivtv_buffer *buf; | ||
74 | struct list_head *p; | ||
75 | u32 bytes_needed = 0; | ||
76 | u32 offset, size; | ||
77 | u32 UVoffset = 0, UVsize = 0; | ||
78 | int skip_bufs = s->q_predma.buffers; | ||
79 | int idx = s->SG_length; | ||
80 | int rc; | ||
81 | |||
82 | /* sanity checks */ | ||
83 | if (s->v4l2dev == NULL) { | ||
84 | IVTV_DEBUG_WARN("Stream %s not started\n", s->name); | ||
85 | return -1; | ||
86 | } | ||
87 | if (!test_bit(IVTV_F_S_CLAIMED, &s->s_flags)) { | ||
88 | IVTV_DEBUG_WARN("Stream %s not open\n", s->name); | ||
89 | return -1; | ||
90 | } | ||
91 | |||
92 | /* determine offset, size and PTS for the various streams */ | ||
93 | switch (s->type) { | ||
94 | case IVTV_ENC_STREAM_TYPE_MPG: | ||
95 | offset = data[1]; | ||
96 | size = data[2]; | ||
97 | s->dma_pts = 0; | ||
98 | break; | ||
99 | |||
100 | case IVTV_ENC_STREAM_TYPE_YUV: | ||
101 | offset = data[1]; | ||
102 | size = data[2]; | ||
103 | UVoffset = data[3]; | ||
104 | UVsize = data[4]; | ||
105 | s->dma_pts = ((u64) data[5] << 32) | data[6]; | ||
106 | break; | ||
107 | |||
108 | case IVTV_ENC_STREAM_TYPE_PCM: | ||
109 | offset = data[1] + 12; | ||
110 | size = data[2] - 12; | ||
111 | s->dma_pts = read_dec(offset - 8) | | ||
112 | ((u64)(read_dec(offset - 12)) << 32); | ||
113 | if (itv->has_cx23415) | ||
114 | offset += IVTV_DECODER_OFFSET; | ||
115 | break; | ||
116 | |||
117 | case IVTV_ENC_STREAM_TYPE_VBI: | ||
118 | size = itv->vbi.enc_size * itv->vbi.fpi; | ||
119 | offset = read_enc(itv->vbi.enc_start - 4) + 12; | ||
120 | if (offset == 12) { | ||
121 | IVTV_DEBUG_INFO("VBI offset == 0\n"); | ||
122 | return -1; | ||
123 | } | ||
124 | s->dma_pts = read_enc(offset - 4) | ((u64)read_enc(offset - 8) << 32); | ||
125 | break; | ||
126 | |||
127 | case IVTV_DEC_STREAM_TYPE_VBI: | ||
128 | size = read_dec(itv->vbi.dec_start + 4) + 8; | ||
129 | offset = read_dec(itv->vbi.dec_start) + itv->vbi.dec_start; | ||
130 | s->dma_pts = 0; | ||
131 | offset += IVTV_DECODER_OFFSET; | ||
132 | break; | ||
133 | default: | ||
134 | /* shouldn't happen */ | ||
135 | return -1; | ||
136 | } | ||
137 | |||
138 | /* if this is the start of the DMA then fill in the magic cookie */ | ||
139 | if (s->SG_length == 0) { | ||
140 | if (itv->has_cx23415 && (s->type == IVTV_ENC_STREAM_TYPE_PCM || | ||
141 | s->type == IVTV_DEC_STREAM_TYPE_VBI)) { | ||
142 | s->dma_backup = read_dec(offset - IVTV_DECODER_OFFSET); | ||
143 | write_dec_sync(cpu_to_le32(DMA_MAGIC_COOKIE), offset - IVTV_DECODER_OFFSET); | ||
144 | } | ||
145 | else { | ||
146 | s->dma_backup = read_enc(offset); | ||
147 | write_enc_sync(cpu_to_le32(DMA_MAGIC_COOKIE), offset); | ||
148 | } | ||
149 | s->dma_offset = offset; | ||
150 | } | ||
151 | |||
152 | bytes_needed = size; | ||
153 | if (s->type == IVTV_ENC_STREAM_TYPE_YUV) { | ||
154 | /* The size for the Y samples needs to be rounded upwards to a | ||
155 | multiple of the buf_size. The UV samples then start in the | ||
156 | next buffer. */ | ||
157 | bytes_needed = s->buf_size * ((bytes_needed + s->buf_size - 1) / s->buf_size); | ||
158 | bytes_needed += UVsize; | ||
159 | } | ||
160 | |||
161 | IVTV_DEBUG_DMA("%s %s: 0x%08x bytes at 0x%08x\n", | ||
162 | ivtv_use_pio(s) ? "PIO" : "DMA", s->name, bytes_needed, offset); | ||
163 | |||
164 | rc = ivtv_queue_move(s, &s->q_free, &s->q_full, &s->q_predma, bytes_needed); | ||
165 | if (rc < 0) { /* Insufficient buffers */ | ||
166 | IVTV_DEBUG_WARN("Cannot obtain %d bytes for %s data transfer\n", | ||
167 | bytes_needed, s->name); | ||
168 | return -1; | ||
169 | } | ||
170 | if (rc && !s->buffers_stolen && (s->s_flags & IVTV_F_S_APPL_IO)) { | ||
171 | IVTV_WARN("All %s stream buffers are full. Dropping data.\n", s->name); | ||
172 | IVTV_WARN("Cause: the application is not reading fast enough.\n"); | ||
173 | } | ||
174 | s->buffers_stolen = rc; | ||
175 | |||
176 | /* got the buffers, now fill in SGarray (DMA) or copy the data from the card | ||
177 | to the buffers (PIO). */ | ||
178 | buf = list_entry(s->q_predma.list.next, struct ivtv_buffer, list); | ||
179 | memset(buf->buf, 0, 128); | ||
180 | list_for_each(p, &s->q_predma.list) { | ||
181 | struct ivtv_buffer *buf = list_entry(p, struct ivtv_buffer, list); | ||
182 | |||
183 | if (skip_bufs-- > 0) | ||
184 | continue; | ||
185 | if (!ivtv_use_pio(s)) { | ||
186 | s->SGarray[idx].dst = cpu_to_le32(buf->dma_handle); | ||
187 | s->SGarray[idx].src = cpu_to_le32(offset); | ||
188 | s->SGarray[idx].size = cpu_to_le32(s->buf_size); | ||
189 | } | ||
190 | buf->bytesused = (size < s->buf_size) ? size : s->buf_size; | ||
191 | |||
192 | /* If PIO, then copy the data from the card to the buffer */ | ||
193 | if (s->type == IVTV_DEC_STREAM_TYPE_VBI) { | ||
194 | memcpy_fromio(buf->buf, itv->dec_mem + offset - IVTV_DECODER_OFFSET, buf->bytesused); | ||
195 | } | ||
196 | else if (ivtv_use_pio(s)) { | ||
197 | memcpy_fromio(buf->buf, itv->enc_mem + offset, buf->bytesused); | ||
198 | } | ||
199 | |||
200 | s->q_predma.bytesused += buf->bytesused; | ||
201 | size -= buf->bytesused; | ||
202 | offset += s->buf_size; | ||
203 | |||
204 | /* Sync SG buffers */ | ||
205 | ivtv_buf_sync_for_device(s, buf); | ||
206 | |||
207 | if (size == 0) { /* YUV */ | ||
208 | /* process the UV section */ | ||
209 | offset = UVoffset; | ||
210 | size = UVsize; | ||
211 | } | ||
212 | idx++; | ||
213 | } | ||
214 | s->SG_length = idx; | ||
215 | return 0; | ||
216 | } | ||
217 | |||
218 | static void dma_post(struct ivtv_stream *s) | ||
219 | { | ||
220 | struct ivtv *itv = s->itv; | ||
221 | struct ivtv_buffer *buf = NULL; | ||
222 | struct list_head *p; | ||
223 | u32 offset; | ||
224 | u32 *u32buf; | ||
225 | int x = 0; | ||
226 | |||
227 | if (ivtv_use_pio(s)) { | ||
228 | if (s->q_predma.bytesused) | ||
229 | ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused); | ||
230 | s->SG_length = 0; | ||
231 | } | ||
232 | IVTV_DEBUG_DMA("%s %s completed (%x)\n", ivtv_use_pio(s) ? "PIO" : "DMA", | ||
233 | s->name, s->dma_offset); | ||
234 | list_for_each(p, &s->q_dma.list) { | ||
235 | buf = list_entry(p, struct ivtv_buffer, list); | ||
236 | u32buf = (u32 *)buf->buf; | ||
237 | |||
238 | /* Sync Buffer */ | ||
239 | ivtv_buf_sync_for_cpu(s, buf); | ||
240 | |||
241 | if (x == 0) { | ||
242 | offset = s->dma_last_offset; | ||
243 | if (u32buf[offset / 4] != DMA_MAGIC_COOKIE) | ||
244 | { | ||
245 | for (offset = 0; offset < 64; offset++) { | ||
246 | if (u32buf[offset] == DMA_MAGIC_COOKIE) { | ||
247 | break; | ||
248 | } | ||
249 | } | ||
250 | offset *= 4; | ||
251 | if (offset == 256) { | ||
252 | IVTV_DEBUG_WARN("%s: Couldn't find start of buffer within the first 256 bytes\n", s->name); | ||
253 | offset = s->dma_last_offset; | ||
254 | } | ||
255 | if (s->dma_last_offset != offset) | ||
256 | IVTV_DEBUG_WARN("%s: offset %d -> %d\n", s->name, s->dma_last_offset, offset); | ||
257 | s->dma_last_offset = offset; | ||
258 | } | ||
259 | if (itv->has_cx23415 && (s->type == IVTV_ENC_STREAM_TYPE_PCM || | ||
260 | s->type == IVTV_DEC_STREAM_TYPE_VBI)) { | ||
261 | write_dec_sync(0, s->dma_offset - IVTV_DECODER_OFFSET); | ||
262 | } | ||
263 | else { | ||
264 | write_enc_sync(0, s->dma_offset); | ||
265 | } | ||
266 | if (offset) { | ||
267 | buf->bytesused -= offset; | ||
268 | memcpy(buf->buf, buf->buf + offset, buf->bytesused + offset); | ||
269 | } | ||
270 | *u32buf = cpu_to_le32(s->dma_backup); | ||
271 | } | ||
272 | x++; | ||
273 | /* flag byteswap ABCD -> DCBA for MPG & VBI data outside irq */ | ||
274 | if (s->type == IVTV_ENC_STREAM_TYPE_MPG || | ||
275 | s->type == IVTV_ENC_STREAM_TYPE_VBI) | ||
276 | set_bit(IVTV_F_B_NEED_BUF_SWAP, &buf->b_flags); | ||
277 | } | ||
278 | if (buf) | ||
279 | buf->bytesused += s->dma_last_offset; | ||
280 | if (buf && s->type == IVTV_DEC_STREAM_TYPE_VBI) { | ||
281 | /* Parse and Groom VBI Data */ | ||
282 | s->q_dma.bytesused -= buf->bytesused; | ||
283 | ivtv_process_vbi_data(itv, buf, 0, s->type); | ||
284 | s->q_dma.bytesused += buf->bytesused; | ||
285 | if (s->id == -1) { | ||
286 | ivtv_queue_move(s, &s->q_dma, NULL, &s->q_free, 0); | ||
287 | return; | ||
288 | } | ||
289 | } | ||
290 | ivtv_queue_move(s, &s->q_dma, NULL, &s->q_full, s->q_dma.bytesused); | ||
291 | if (s->id != -1) | ||
292 | wake_up(&s->waitq); | ||
293 | } | ||
294 | |||
295 | void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock) | ||
296 | { | ||
297 | struct ivtv *itv = s->itv; | ||
298 | struct ivtv_buffer *buf; | ||
299 | struct list_head *p; | ||
300 | u32 y_size = itv->params.height * itv->params.width; | ||
301 | u32 uv_offset = offset + IVTV_YUV_BUFFER_UV_OFFSET; | ||
302 | int y_done = 0; | ||
303 | int bytes_written = 0; | ||
304 | unsigned long flags = 0; | ||
305 | int idx = 0; | ||
306 | |||
307 | IVTV_DEBUG_DMA("DEC PREPARE DMA %s: %08x %08x\n", s->name, s->q_predma.bytesused, offset); | ||
308 | buf = list_entry(s->q_predma.list.next, struct ivtv_buffer, list); | ||
309 | list_for_each(p, &s->q_predma.list) { | ||
310 | struct ivtv_buffer *buf = list_entry(p, struct ivtv_buffer, list); | ||
311 | |||
312 | /* YUV UV Offset from Y Buffer */ | ||
313 | if (s->type == IVTV_DEC_STREAM_TYPE_YUV && !y_done && bytes_written >= y_size) { | ||
314 | offset = uv_offset; | ||
315 | y_done = 1; | ||
316 | } | ||
317 | s->SGarray[idx].src = cpu_to_le32(buf->dma_handle); | ||
318 | s->SGarray[idx].dst = cpu_to_le32(offset); | ||
319 | s->SGarray[idx].size = cpu_to_le32(buf->bytesused); | ||
320 | |||
321 | offset += buf->bytesused; | ||
322 | bytes_written += buf->bytesused; | ||
323 | |||
324 | /* Sync SG buffers */ | ||
325 | ivtv_buf_sync_for_device(s, buf); | ||
326 | idx++; | ||
327 | } | ||
328 | s->SG_length = idx; | ||
329 | |||
330 | /* Mark last buffer size for Interrupt flag */ | ||
331 | s->SGarray[s->SG_length - 1].size |= cpu_to_le32(0x80000000); | ||
332 | |||
333 | /* Sync Hardware SG List of buffers */ | ||
334 | ivtv_stream_sync_for_device(s); | ||
335 | if (lock) | ||
336 | spin_lock_irqsave(&itv->dma_reg_lock, flags); | ||
337 | if (!test_bit(IVTV_F_I_DMA, &itv->i_flags)) { | ||
338 | ivtv_dma_dec_start(s); | ||
339 | } | ||
340 | else { | ||
341 | set_bit(IVTV_F_S_DMA_PENDING, &s->s_flags); | ||
342 | } | ||
343 | if (lock) | ||
344 | spin_unlock_irqrestore(&itv->dma_reg_lock, flags); | ||
345 | } | ||
346 | |||
347 | /* start the encoder DMA */ | ||
348 | static void ivtv_dma_enc_start(struct ivtv_stream *s) | ||
349 | { | ||
350 | struct ivtv *itv = s->itv; | ||
351 | struct ivtv_stream *s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; | ||
352 | int i; | ||
353 | |||
354 | if (s->q_predma.bytesused) | ||
355 | ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused); | ||
356 | IVTV_DEBUG_DMA("start DMA for %s\n", s->name); | ||
357 | s->SGarray[s->SG_length - 1].size = cpu_to_le32(le32_to_cpu(s->SGarray[s->SG_length - 1].size) + 256); | ||
358 | |||
359 | /* If this is an MPEG stream, and VBI data is also pending, then append the | ||
360 | VBI DMA to the MPEG DMA and transfer both sets of data at once. | ||
361 | |||
362 | VBI DMA is a second class citizen compared to MPEG and mixing them together | ||
363 | will confuse the firmware (the end of a VBI DMA is seen as the end of a | ||
364 | MPEG DMA, thus effectively dropping an MPEG frame). So instead we make | ||
365 | sure we only use the MPEG DMA to transfer the VBI DMA if both are in | ||
366 | use. This way no conflicts occur. */ | ||
367 | clear_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags); | ||
368 | if (s->type == IVTV_ENC_STREAM_TYPE_MPG && s_vbi->SG_length && | ||
369 | s->SG_length + s_vbi->SG_length <= s->buffers) { | ||
370 | ivtv_queue_move(s_vbi, &s_vbi->q_predma, NULL, &s_vbi->q_dma, s_vbi->q_predma.bytesused); | ||
371 | s_vbi->SGarray[s_vbi->SG_length - 1].size = cpu_to_le32(le32_to_cpu(s_vbi->SGarray[s->SG_length - 1].size) + 256); | ||
372 | for (i = 0; i < s_vbi->SG_length; i++) { | ||
373 | s->SGarray[s->SG_length++] = s_vbi->SGarray[i]; | ||
374 | } | ||
375 | itv->vbi.dma_offset = s_vbi->dma_offset; | ||
376 | s_vbi->SG_length = 0; | ||
377 | set_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags); | ||
378 | IVTV_DEBUG_DMA("include DMA for %s\n", s->name); | ||
379 | } | ||
380 | |||
381 | /* Mark last buffer size for Interrupt flag */ | ||
382 | s->SGarray[s->SG_length - 1].size |= cpu_to_le32(0x80000000); | ||
383 | |||
384 | /* Sync Hardware SG List of buffers */ | ||
385 | ivtv_stream_sync_for_device(s); | ||
386 | write_reg(s->SG_handle, IVTV_REG_ENCDMAADDR); | ||
387 | write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x02, IVTV_REG_DMAXFER); | ||
388 | set_bit(IVTV_F_I_DMA, &itv->i_flags); | ||
389 | itv->cur_dma_stream = s->type; | ||
390 | itv->dma_timer.expires = jiffies + HZ / 10; | ||
391 | add_timer(&itv->dma_timer); | ||
392 | } | ||
393 | |||
394 | static void ivtv_dma_dec_start(struct ivtv_stream *s) | ||
395 | { | ||
396 | struct ivtv *itv = s->itv; | ||
397 | |||
398 | if (s->q_predma.bytesused) | ||
399 | ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused); | ||
400 | IVTV_DEBUG_DMA("start DMA for %s\n", s->name); | ||
401 | /* put SG Handle into register 0x0c */ | ||
402 | write_reg(s->SG_handle, IVTV_REG_DECDMAADDR); | ||
403 | write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x01, IVTV_REG_DMAXFER); | ||
404 | set_bit(IVTV_F_I_DMA, &itv->i_flags); | ||
405 | itv->cur_dma_stream = s->type; | ||
406 | itv->dma_timer.expires = jiffies + HZ / 10; | ||
407 | add_timer(&itv->dma_timer); | ||
408 | } | ||
409 | |||
410 | static void ivtv_irq_dma_read(struct ivtv *itv) | ||
411 | { | ||
412 | struct ivtv_stream *s = NULL; | ||
413 | struct ivtv_buffer *buf; | ||
414 | int hw_stream_type; | ||
415 | |||
416 | IVTV_DEBUG_IRQ("DEC DMA READ\n"); | ||
417 | del_timer(&itv->dma_timer); | ||
418 | if (read_reg(IVTV_REG_DMASTATUS) & 0x14) { | ||
419 | IVTV_DEBUG_WARN("DEC DMA ERROR %x\n", read_reg(IVTV_REG_DMASTATUS)); | ||
420 | write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS); | ||
421 | } | ||
422 | if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags)) { | ||
423 | if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) { | ||
424 | s = &itv->streams[IVTV_DEC_STREAM_TYPE_YUV]; | ||
425 | hw_stream_type = 2; | ||
426 | } | ||
427 | else { | ||
428 | s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG]; | ||
429 | hw_stream_type = 0; | ||
430 | } | ||
431 | IVTV_DEBUG_DMA("DEC DATA READ %s: %d\n", s->name, s->q_dma.bytesused); | ||
432 | |||
433 | ivtv_stream_sync_for_cpu(s); | ||
434 | |||
435 | /* For some reason must kick the firmware, like PIO mode, | ||
436 | I think this tells the firmware we are done and the size | ||
437 | of the xfer so it can calculate what we need next. | ||
438 | I think we can do this part ourselves but would have to | ||
439 | fully calculate xfer info ourselves and not use interrupts | ||
440 | */ | ||
441 | ivtv_vapi(itv, CX2341X_DEC_SCHED_DMA_FROM_HOST, 3, 0, s->q_dma.bytesused, | ||
442 | hw_stream_type); | ||
443 | |||
444 | /* Free last DMA call */ | ||
445 | while ((buf = ivtv_dequeue(s, &s->q_dma)) != NULL) { | ||
446 | ivtv_buf_sync_for_cpu(s, buf); | ||
447 | ivtv_enqueue(s, buf, &s->q_free); | ||
448 | } | ||
449 | wake_up(&s->waitq); | ||
450 | } | ||
451 | clear_bit(IVTV_F_I_UDMA, &itv->i_flags); | ||
452 | clear_bit(IVTV_F_I_DMA, &itv->i_flags); | ||
453 | itv->cur_dma_stream = -1; | ||
454 | wake_up(&itv->dma_waitq); | ||
455 | } | ||
456 | |||
457 | static void ivtv_irq_enc_dma_complete(struct ivtv *itv) | ||
458 | { | ||
459 | u32 data[CX2341X_MBOX_MAX_DATA]; | ||
460 | struct ivtv_stream *s; | ||
461 | |||
462 | del_timer(&itv->dma_timer); | ||
463 | ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA_END, data); | ||
464 | IVTV_DEBUG_IRQ("ENC DMA COMPLETE %x %d\n", data[0], data[1]); | ||
465 | if (test_and_clear_bit(IVTV_F_I_ENC_VBI, &itv->i_flags)) | ||
466 | data[1] = 3; | ||
467 | else if (data[1] > 2) | ||
468 | return; | ||
469 | s = &itv->streams[ivtv_stream_map[data[1]]]; | ||
470 | if (data[0] & 0x18) { | ||
471 | IVTV_DEBUG_WARN("ENC DMA ERROR %x\n", data[0]); | ||
472 | write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS); | ||
473 | ivtv_vapi(itv, CX2341X_ENC_SCHED_DMA_TO_HOST, 3, 0, 0, data[1]); | ||
474 | } | ||
475 | s->SG_length = 0; | ||
476 | clear_bit(IVTV_F_I_DMA, &itv->i_flags); | ||
477 | itv->cur_dma_stream = -1; | ||
478 | dma_post(s); | ||
479 | ivtv_stream_sync_for_cpu(s); | ||
480 | if (test_and_clear_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags)) { | ||
481 | u32 tmp; | ||
482 | |||
483 | s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; | ||
484 | tmp = s->dma_offset; | ||
485 | s->dma_offset = itv->vbi.dma_offset; | ||
486 | dma_post(s); | ||
487 | s->dma_offset = tmp; | ||
488 | } | ||
489 | wake_up(&itv->dma_waitq); | ||
490 | } | ||
491 | |||
492 | static void ivtv_irq_dma_err(struct ivtv *itv) | ||
493 | { | ||
494 | u32 data[CX2341X_MBOX_MAX_DATA]; | ||
495 | |||
496 | del_timer(&itv->dma_timer); | ||
497 | ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA_END, data); | ||
498 | IVTV_DEBUG_WARN("DMA ERROR %08x %08x %08x %d\n", data[0], data[1], | ||
499 | read_reg(IVTV_REG_DMASTATUS), itv->cur_dma_stream); | ||
500 | if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags) && | ||
501 | itv->cur_dma_stream >= 0 && itv->cur_dma_stream < IVTV_MAX_STREAMS) { | ||
502 | struct ivtv_stream *s = &itv->streams[itv->cur_dma_stream]; | ||
503 | |||
504 | /* retry */ | ||
505 | write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS); | ||
506 | if (s->type >= IVTV_DEC_STREAM_TYPE_MPG) | ||
507 | ivtv_dma_dec_start(s); | ||
508 | else | ||
509 | ivtv_dma_enc_start(s); | ||
510 | return; | ||
511 | } | ||
512 | clear_bit(IVTV_F_I_UDMA, &itv->i_flags); | ||
513 | clear_bit(IVTV_F_I_DMA, &itv->i_flags); | ||
514 | itv->cur_dma_stream = -1; | ||
515 | wake_up(&itv->dma_waitq); | ||
516 | } | ||
517 | |||
518 | static void ivtv_irq_enc_start_cap(struct ivtv *itv) | ||
519 | { | ||
520 | u32 data[CX2341X_MBOX_MAX_DATA]; | ||
521 | struct ivtv_stream *s; | ||
522 | |||
523 | /* Get DMA destination and size arguments from card */ | ||
524 | ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA, data); | ||
525 | IVTV_DEBUG_IRQ("ENC START CAP %d: %08x %08x\n", data[0], data[1], data[2]); | ||
526 | |||
527 | if (data[0] > 2 || data[1] == 0 || data[2] == 0) { | ||
528 | IVTV_DEBUG_WARN("Unknown input: %08x %08x %08x\n", | ||
529 | data[0], data[1], data[2]); | ||
530 | return; | ||
531 | } | ||
532 | clear_bit(IVTV_F_I_ENC_VBI, &itv->i_flags); | ||
533 | s = &itv->streams[ivtv_stream_map[data[0]]]; | ||
534 | if (!stream_enc_dma_append(s, data)) { | ||
535 | if (ivtv_use_pio(s)) { | ||
536 | dma_post(s); | ||
537 | ivtv_vapi(itv, CX2341X_ENC_SCHED_DMA_TO_HOST, 3, 0, 0, data[0]); | ||
538 | } | ||
539 | else { | ||
540 | set_bit(IVTV_F_S_DMA_PENDING, &s->s_flags); | ||
541 | } | ||
542 | } | ||
543 | } | ||
544 | |||
545 | static void ivtv_irq_enc_vbi_cap(struct ivtv *itv) | ||
546 | { | ||
547 | struct ivtv_stream *s_mpg = &itv->streams[IVTV_ENC_STREAM_TYPE_MPG]; | ||
548 | u32 data[CX2341X_MBOX_MAX_DATA]; | ||
549 | struct ivtv_stream *s; | ||
550 | |||
551 | IVTV_DEBUG_IRQ("ENC START VBI CAP\n"); | ||
552 | s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; | ||
553 | |||
554 | if (ivtv_use_pio(s)) { | ||
555 | if (stream_enc_dma_append(s, data)) | ||
556 | return; | ||
557 | if (s->q_predma.bytesused) | ||
558 | ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused); | ||
559 | s->SG_length = 0; | ||
560 | dma_post(s); | ||
561 | return; | ||
562 | } | ||
563 | /* If more than two VBI buffers are pending, then | ||
564 | clear the old ones and start with this new one. | ||
565 | This can happen during transition stages when MPEG capturing is | ||
566 | started, but the first interrupts haven't arrived yet. During | ||
567 | that period VBI requests can accumulate without being able to | ||
568 | DMA the data. Since at most four VBI DMA buffers are available, | ||
569 | we just drop the old requests when there are already three | ||
570 | requests queued. */ | ||
571 | if (s->SG_length > 2) { | ||
572 | struct list_head *p; | ||
573 | list_for_each(p, &s->q_predma.list) { | ||
574 | struct ivtv_buffer *buf = list_entry(p, struct ivtv_buffer, list); | ||
575 | ivtv_buf_sync_for_cpu(s, buf); | ||
576 | } | ||
577 | ivtv_queue_move(s, &s->q_predma, NULL, &s->q_free, 0); | ||
578 | s->SG_length = 0; | ||
579 | } | ||
580 | /* if we can append the data, and the MPEG stream isn't capturing, | ||
581 | then start a DMA request for just the VBI data. */ | ||
582 | if (!stream_enc_dma_append(s, data) && | ||
583 | !test_bit(IVTV_F_S_STREAMING, &s_mpg->s_flags)) { | ||
584 | set_bit(IVTV_F_I_ENC_VBI, &itv->i_flags); | ||
585 | set_bit(IVTV_F_S_DMA_PENDING, &s->s_flags); | ||
586 | } | ||
587 | } | ||
588 | |||
589 | static void ivtv_irq_dev_vbi_reinsert(struct ivtv *itv) | ||
590 | { | ||
591 | u32 data[CX2341X_MBOX_MAX_DATA]; | ||
592 | struct ivtv_stream *s = &itv->streams[IVTV_DEC_STREAM_TYPE_VBI]; | ||
593 | |||
594 | IVTV_DEBUG_IRQ("DEC VBI REINSERT\n"); | ||
595 | if (test_bit(IVTV_F_S_CLAIMED, &s->s_flags) && | ||
596 | !stream_enc_dma_append(s, data)) { | ||
597 | dma_post(s); | ||
598 | } | ||
599 | } | ||
600 | |||
601 | static void ivtv_irq_dec_data_req(struct ivtv *itv) | ||
602 | { | ||
603 | u32 data[CX2341X_MBOX_MAX_DATA]; | ||
604 | struct ivtv_stream *s; | ||
605 | |||
606 | /* YUV or MPG */ | ||
607 | ivtv_api_get_data(&itv->dec_mbox, IVTV_MBOX_DMA, data); | ||
608 | |||
609 | if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) { | ||
610 | itv->dma_data_req_size = itv->params.width * itv->params.height * 3 / 2; | ||
611 | itv->dma_data_req_offset = data[1] ? data[1] : yuv_offset[0]; | ||
612 | s = &itv->streams[IVTV_DEC_STREAM_TYPE_YUV]; | ||
613 | } | ||
614 | else { | ||
615 | itv->dma_data_req_size = data[2] >= 0x10000 ? 0x10000 : data[2]; | ||
616 | itv->dma_data_req_offset = data[1]; | ||
617 | s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG]; | ||
618 | } | ||
619 | IVTV_DEBUG_IRQ("DEC DATA REQ %s: %d %08x %u\n", s->name, s->q_full.bytesused, | ||
620 | itv->dma_data_req_offset, itv->dma_data_req_size); | ||
621 | if (itv->dma_data_req_size == 0 || s->q_full.bytesused < itv->dma_data_req_size) { | ||
622 | set_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags); | ||
623 | } | ||
624 | else { | ||
625 | clear_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags); | ||
626 | ivtv_queue_move(s, &s->q_full, NULL, &s->q_predma, itv->dma_data_req_size); | ||
627 | ivtv_dma_stream_dec_prepare(s, itv->dma_data_req_offset + IVTV_DECODER_OFFSET, 0); | ||
628 | } | ||
629 | } | ||
630 | |||
631 | static void ivtv_irq_vsync(struct ivtv *itv) | ||
632 | { | ||
633 | /* The vsync interrupt is unusual in that it won't clear until | ||
634 | * the end of the first line for the current field, at which | ||
635 | * point it clears itself. This can result in repeated vsync | ||
636 | * interrupts, or a missed vsync. Read some of the registers | ||
637 | * to determine the line being displayed and ensure we handle | ||
638 | * one vsync per frame. | ||
639 | */ | ||
640 | unsigned int frame = read_reg(0x28c0) & 1; | ||
641 | int last_dma_frame = atomic_read(&itv->yuv_info.next_dma_frame); | ||
642 | |||
643 | if (0) IVTV_DEBUG_IRQ("DEC VSYNC\n"); | ||
644 | |||
645 | if (((frame ^ itv->yuv_info.lace_sync_field) == 0 && ((itv->lastVsyncFrame & 1) ^ itv->yuv_info.lace_sync_field)) || | ||
646 | (frame != (itv->lastVsyncFrame & 1) && !itv->yuv_info.frame_interlaced)) { | ||
647 | int next_dma_frame = last_dma_frame; | ||
648 | |||
649 | if (next_dma_frame >= 0 && next_dma_frame != atomic_read(&itv->yuv_info.next_fill_frame)) { | ||
650 | write_reg(yuv_offset[next_dma_frame] >> 4, 0x82c); | ||
651 | write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x830); | ||
652 | write_reg(yuv_offset[next_dma_frame] >> 4, 0x834); | ||
653 | write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x838); | ||
654 | next_dma_frame = (next_dma_frame + 1) & 0x3; | ||
655 | atomic_set(&itv->yuv_info.next_dma_frame, next_dma_frame); | ||
656 | } | ||
657 | } | ||
658 | if (frame != (itv->lastVsyncFrame & 1)) { | ||
659 | struct ivtv_stream *s = ivtv_get_output_stream(itv); | ||
660 | int work = 0; | ||
661 | |||
662 | itv->lastVsyncFrame += 1; | ||
663 | if (frame == 0) { | ||
664 | clear_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags); | ||
665 | clear_bit(IVTV_F_I_EV_VSYNC_FIELD, &itv->i_flags); | ||
666 | } | ||
667 | else { | ||
668 | set_bit(IVTV_F_I_EV_VSYNC_FIELD, &itv->i_flags); | ||
669 | } | ||
670 | if (test_bit(IVTV_F_I_EV_VSYNC_ENABLED, &itv->i_flags)) { | ||
671 | set_bit(IVTV_F_I_EV_VSYNC, &itv->i_flags); | ||
672 | wake_up(&itv->event_waitq); | ||
673 | } | ||
674 | wake_up(&itv->vsync_waitq); | ||
675 | if (s) | ||
676 | wake_up(&s->waitq); | ||
677 | |||
678 | /* Send VBI to saa7127 */ | ||
679 | if (frame) { | ||
680 | set_bit(IVTV_F_I_WORK_HANDLER_VBI, &itv->i_flags); | ||
681 | work = 1; | ||
682 | } | ||
683 | |||
684 | /* Check if we need to update the yuv registers */ | ||
685 | if ((itv->yuv_info.yuv_forced_update || itv->yuv_info.new_frame_info[last_dma_frame].update) && last_dma_frame != -1) { | ||
686 | if (!itv->yuv_info.new_frame_info[last_dma_frame].update) | ||
687 | last_dma_frame = (last_dma_frame - 1) & 3; | ||
688 | |||
689 | if (itv->yuv_info.new_frame_info[last_dma_frame].src_w) { | ||
690 | itv->yuv_info.update_frame = last_dma_frame; | ||
691 | itv->yuv_info.new_frame_info[last_dma_frame].update = 0; | ||
692 | itv->yuv_info.yuv_forced_update = 0; | ||
693 | set_bit(IVTV_F_I_WORK_HANDLER_YUV, &itv->i_flags); | ||
694 | work = 1; | ||
695 | } | ||
696 | } | ||
697 | if (work) | ||
698 | queue_work(itv->irq_work_queues, &itv->irq_work_queue); | ||
699 | } | ||
700 | } | ||
701 | |||
702 | #define IVTV_IRQ_DMA (IVTV_IRQ_DMA_READ | IVTV_IRQ_ENC_DMA_COMPLETE | IVTV_IRQ_DMA_ERR | IVTV_IRQ_ENC_START_CAP | IVTV_IRQ_ENC_VBI_CAP | IVTV_IRQ_DEC_DATA_REQ) | ||
703 | |||
704 | irqreturn_t ivtv_irq_handler(int irq, void *dev_id) | ||
705 | { | ||
706 | struct ivtv *itv = (struct ivtv *)dev_id; | ||
707 | u32 combo; | ||
708 | u32 stat; | ||
709 | int i; | ||
710 | u8 vsync_force = 0; | ||
711 | |||
712 | spin_lock(&itv->dma_reg_lock); | ||
713 | /* get contents of irq status register */ | ||
714 | stat = read_reg(IVTV_REG_IRQSTATUS); | ||
715 | |||
716 | combo = ~itv->irqmask & stat; | ||
717 | |||
718 | /* Clear out IRQ */ | ||
719 | if (combo) write_reg(combo, IVTV_REG_IRQSTATUS); | ||
720 | |||
721 | if (0 == combo) { | ||
722 | /* The vsync interrupt is unusual and clears itself. If we | ||
723 | * took too long, we may have missed it. Do some checks | ||
724 | */ | ||
725 | if (~itv->irqmask & IVTV_IRQ_DEC_VSYNC) { | ||
726 | /* vsync is enabled, see if we're in a new field */ | ||
727 | if ((itv->lastVsyncFrame & 1) != (read_reg(0x28c0) & 1)) { | ||
728 | /* New field, looks like we missed it */ | ||
729 | IVTV_DEBUG_YUV("VSync interrupt missed %d\n",read_reg(0x28c0)>>16); | ||
730 | vsync_force = 1; | ||
731 | } | ||
732 | } | ||
733 | |||
734 | if (!vsync_force) { | ||
735 | /* No Vsync expected, wasn't for us */ | ||
736 | spin_unlock(&itv->dma_reg_lock); | ||
737 | return IRQ_NONE; | ||
738 | } | ||
739 | } | ||
740 | |||
741 | /* Exclude interrupts noted below from the output, otherwise the log is flooded with | ||
742 | these messages */ | ||
743 | if (combo & ~0xff6d0400) | ||
744 | IVTV_DEBUG_IRQ("======= valid IRQ bits: 0x%08x ======\n", combo); | ||
745 | |||
746 | if (combo & IVTV_IRQ_DEC_DMA_COMPLETE) { | ||
747 | IVTV_DEBUG_IRQ("DEC DMA COMPLETE\n"); | ||
748 | } | ||
749 | |||
750 | if (combo & IVTV_IRQ_DMA_READ) { | ||
751 | ivtv_irq_dma_read(itv); | ||
752 | } | ||
753 | |||
754 | if (combo & IVTV_IRQ_ENC_DMA_COMPLETE) { | ||
755 | ivtv_irq_enc_dma_complete(itv); | ||
756 | } | ||
757 | |||
758 | if (combo & IVTV_IRQ_DMA_ERR) { | ||
759 | ivtv_irq_dma_err(itv); | ||
760 | } | ||
761 | |||
762 | if (combo & IVTV_IRQ_ENC_START_CAP) { | ||
763 | ivtv_irq_enc_start_cap(itv); | ||
764 | } | ||
765 | |||
766 | if (combo & IVTV_IRQ_ENC_VBI_CAP) { | ||
767 | ivtv_irq_enc_vbi_cap(itv); | ||
768 | } | ||
769 | |||
770 | if (combo & IVTV_IRQ_DEC_VBI_RE_INSERT) { | ||
771 | ivtv_irq_dev_vbi_reinsert(itv); | ||
772 | } | ||
773 | |||
774 | if (combo & IVTV_IRQ_ENC_EOS) { | ||
775 | IVTV_DEBUG_IRQ("ENC EOS\n"); | ||
776 | set_bit(IVTV_F_I_EOS, &itv->i_flags); | ||
777 | wake_up(&itv->cap_w); | ||
778 | } | ||
779 | |||
780 | if (combo & IVTV_IRQ_DEC_DATA_REQ) { | ||
781 | ivtv_irq_dec_data_req(itv); | ||
782 | } | ||
783 | |||
784 | /* Decoder Vertical Sync - We can't rely on 'combo', so check if vsync enabled */ | ||
785 | if (~itv->irqmask & IVTV_IRQ_DEC_VSYNC) { | ||
786 | ivtv_irq_vsync(itv); | ||
787 | } | ||
788 | |||
789 | if (combo & IVTV_IRQ_ENC_VIM_RST) { | ||
790 | IVTV_DEBUG_IRQ("VIM RST\n"); | ||
791 | /*ivtv_vapi(itv, CX2341X_ENC_REFRESH_INPUT, 0); */ | ||
792 | } | ||
793 | |||
794 | if (combo & IVTV_IRQ_DEC_AUD_MODE_CHG) { | ||
795 | IVTV_DEBUG_INFO("Stereo mode changed\n"); | ||
796 | } | ||
797 | |||
798 | if ((combo & IVTV_IRQ_DMA) && !test_bit(IVTV_F_I_DMA, &itv->i_flags)) { | ||
799 | for (i = 0; i < IVTV_MAX_STREAMS; i++) { | ||
800 | int idx = (i + itv->irq_rr_idx++) % IVTV_MAX_STREAMS; | ||
801 | struct ivtv_stream *s = &itv->streams[idx]; | ||
802 | |||
803 | if (!test_and_clear_bit(IVTV_F_S_DMA_PENDING, &s->s_flags)) | ||
804 | continue; | ||
805 | if (s->type >= IVTV_DEC_STREAM_TYPE_MPG) | ||
806 | ivtv_dma_dec_start(s); | ||
807 | else | ||
808 | ivtv_dma_enc_start(s); | ||
809 | break; | ||
810 | } | ||
811 | if (i == IVTV_MAX_STREAMS && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags)) { | ||
812 | ivtv_udma_start(itv); | ||
813 | } | ||
814 | } | ||
815 | |||
816 | spin_unlock(&itv->dma_reg_lock); | ||
817 | |||
818 | /* If we've just handled a 'forced' vsync, it's safest to say it | ||
819 | * wasn't ours. Another device may have triggered it at just | ||
820 | * the right time. | ||
821 | */ | ||
822 | return vsync_force ? IRQ_NONE : IRQ_HANDLED; | ||
823 | } | ||
824 | |||
825 | void ivtv_unfinished_dma(unsigned long arg) | ||
826 | { | ||
827 | struct ivtv *itv = (struct ivtv *)arg; | ||
828 | |||
829 | if (!test_bit(IVTV_F_I_DMA, &itv->i_flags)) | ||
830 | return; | ||
831 | IVTV_ERR("DMA TIMEOUT %08x %d\n", read_reg(IVTV_REG_DMASTATUS), itv->cur_dma_stream); | ||
832 | |||
833 | write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS); | ||
834 | clear_bit(IVTV_F_I_UDMA, &itv->i_flags); | ||
835 | clear_bit(IVTV_F_I_DMA, &itv->i_flags); | ||
836 | itv->cur_dma_stream = -1; | ||
837 | wake_up(&itv->dma_waitq); | ||
838 | } | ||
diff --git a/drivers/media/video/ivtv/ivtv-irq.h b/drivers/media/video/ivtv/ivtv-irq.h new file mode 100644 index 000000000000..a43348a30309 --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-irq.h | |||
@@ -0,0 +1,26 @@ | |||
1 | /* | ||
2 | interrupt handling | ||
3 | Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> | ||
4 | Copyright (C) 2004 Chris Kennedy <c@groovy.org> | ||
5 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2 of the License, or | ||
10 | (at your option) any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; if not, write to the Free Software | ||
19 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | */ | ||
21 | |||
22 | irqreturn_t ivtv_irq_handler(int irq, void *dev_id); | ||
23 | |||
24 | void ivtv_irq_work_handler(struct work_struct *work); | ||
25 | void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock); | ||
26 | void ivtv_unfinished_dma(unsigned long arg); | ||
diff --git a/drivers/media/video/ivtv/ivtv-mailbox.c b/drivers/media/video/ivtv/ivtv-mailbox.c new file mode 100644 index 000000000000..6ae42a3b03cc --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-mailbox.c | |||
@@ -0,0 +1,360 @@ | |||
1 | /* | ||
2 | mailbox functions | ||
3 | Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> | ||
4 | Copyright (C) 2004 Chris Kennedy <c@groovy.org> | ||
5 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2 of the License, or | ||
10 | (at your option) any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; if not, write to the Free Software | ||
19 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | */ | ||
21 | |||
22 | #include <stdarg.h> | ||
23 | |||
24 | #include "ivtv-driver.h" | ||
25 | #include "ivtv-mailbox.h" | ||
26 | |||
27 | /* Firmware mailbox flags*/ | ||
28 | #define IVTV_MBOX_FIRMWARE_DONE 0x00000004 | ||
29 | #define IVTV_MBOX_DRIVER_DONE 0x00000002 | ||
30 | #define IVTV_MBOX_DRIVER_BUSY 0x00000001 | ||
31 | #define IVTV_MBOX_FREE 0x00000000 | ||
32 | |||
33 | /* Firmware mailbox standard timeout */ | ||
34 | #define IVTV_API_STD_TIMEOUT 0x02000000 | ||
35 | |||
36 | #define API_CACHE (1 << 0) /* Allow the command to be stored in the cache */ | ||
37 | #define API_RESULT (1 << 1) /* Allow 1 second for this cmd to end */ | ||
38 | #define API_FAST_RESULT (3 << 1) /* Allow 0.1 second for this cmd to end */ | ||
39 | #define API_DMA (1 << 3) /* DMA mailbox, has special handling */ | ||
40 | #define API_NO_WAIT_MB (1 << 4) /* Command may not wait for a free mailbox */ | ||
41 | #define API_NO_WAIT_RES (1 << 5) /* Command may not wait for the result */ | ||
42 | |||
43 | struct ivtv_api_info { | ||
44 | int flags; /* Flags, see above */ | ||
45 | const char *name; /* The name of the command */ | ||
46 | }; | ||
47 | |||
48 | #define API_ENTRY(x, f) [x] = { (f), #x } | ||
49 | |||
50 | static const struct ivtv_api_info api_info[256] = { | ||
51 | /* MPEG encoder API */ | ||
52 | API_ENTRY(CX2341X_ENC_PING_FW, API_FAST_RESULT), | ||
53 | API_ENTRY(CX2341X_ENC_START_CAPTURE, API_RESULT), | ||
54 | API_ENTRY(CX2341X_ENC_STOP_CAPTURE, API_RESULT), | ||
55 | API_ENTRY(CX2341X_ENC_SET_AUDIO_ID, API_CACHE), | ||
56 | API_ENTRY(CX2341X_ENC_SET_VIDEO_ID, API_CACHE), | ||
57 | API_ENTRY(CX2341X_ENC_SET_PCR_ID, API_CACHE), | ||
58 | API_ENTRY(CX2341X_ENC_SET_FRAME_RATE, API_CACHE), | ||
59 | API_ENTRY(CX2341X_ENC_SET_FRAME_SIZE, API_CACHE), | ||
60 | API_ENTRY(CX2341X_ENC_SET_BIT_RATE, API_CACHE), | ||
61 | API_ENTRY(CX2341X_ENC_SET_GOP_PROPERTIES, API_CACHE), | ||
62 | API_ENTRY(CX2341X_ENC_SET_ASPECT_RATIO, API_CACHE), | ||
63 | API_ENTRY(CX2341X_ENC_SET_DNR_FILTER_MODE, API_CACHE), | ||
64 | API_ENTRY(CX2341X_ENC_SET_DNR_FILTER_PROPS, API_CACHE), | ||
65 | API_ENTRY(CX2341X_ENC_SET_CORING_LEVELS, API_CACHE), | ||
66 | API_ENTRY(CX2341X_ENC_SET_SPATIAL_FILTER_TYPE, API_CACHE), | ||
67 | API_ENTRY(CX2341X_ENC_SET_VBI_LINE, API_RESULT), | ||
68 | API_ENTRY(CX2341X_ENC_SET_STREAM_TYPE, API_CACHE), | ||
69 | API_ENTRY(CX2341X_ENC_SET_OUTPUT_PORT, API_CACHE), | ||
70 | API_ENTRY(CX2341X_ENC_SET_AUDIO_PROPERTIES, API_CACHE), | ||
71 | API_ENTRY(CX2341X_ENC_HALT_FW, API_FAST_RESULT), | ||
72 | API_ENTRY(CX2341X_ENC_GET_VERSION, API_FAST_RESULT), | ||
73 | API_ENTRY(CX2341X_ENC_SET_GOP_CLOSURE, API_CACHE), | ||
74 | API_ENTRY(CX2341X_ENC_GET_SEQ_END, API_RESULT), | ||
75 | API_ENTRY(CX2341X_ENC_SET_PGM_INDEX_INFO, API_FAST_RESULT), | ||
76 | API_ENTRY(CX2341X_ENC_SET_VBI_CONFIG, API_RESULT), | ||
77 | API_ENTRY(CX2341X_ENC_SET_DMA_BLOCK_SIZE, API_CACHE), | ||
78 | API_ENTRY(CX2341X_ENC_GET_PREV_DMA_INFO_MB_10, API_FAST_RESULT), | ||
79 | API_ENTRY(CX2341X_ENC_GET_PREV_DMA_INFO_MB_9, API_FAST_RESULT), | ||
80 | API_ENTRY(CX2341X_ENC_SCHED_DMA_TO_HOST, API_DMA), | ||
81 | API_ENTRY(CX2341X_ENC_INITIALIZE_INPUT, API_RESULT), | ||
82 | API_ENTRY(CX2341X_ENC_SET_FRAME_DROP_RATE, API_CACHE), | ||
83 | API_ENTRY(CX2341X_ENC_PAUSE_ENCODER, API_RESULT), | ||
84 | API_ENTRY(CX2341X_ENC_REFRESH_INPUT, API_NO_WAIT_MB), | ||
85 | API_ENTRY(CX2341X_ENC_SET_COPYRIGHT, API_CACHE), | ||
86 | API_ENTRY(CX2341X_ENC_SET_EVENT_NOTIFICATION, API_RESULT), | ||
87 | API_ENTRY(CX2341X_ENC_SET_NUM_VSYNC_LINES, API_CACHE), | ||
88 | API_ENTRY(CX2341X_ENC_SET_PLACEHOLDER, API_CACHE), | ||
89 | API_ENTRY(CX2341X_ENC_MUTE_VIDEO, API_RESULT), | ||
90 | API_ENTRY(CX2341X_ENC_MUTE_AUDIO, API_RESULT), | ||
91 | API_ENTRY(CX2341X_ENC_SET_VERT_CROP_LINE, API_FAST_RESULT), | ||
92 | API_ENTRY(CX2341X_ENC_MISC, API_FAST_RESULT), | ||
93 | /* Obsolete PULLDOWN API command */ | ||
94 | API_ENTRY(0xb1, API_CACHE), | ||
95 | |||
96 | /* MPEG decoder API */ | ||
97 | API_ENTRY(CX2341X_DEC_PING_FW, API_FAST_RESULT), | ||
98 | API_ENTRY(CX2341X_DEC_START_PLAYBACK, API_RESULT), | ||
99 | API_ENTRY(CX2341X_DEC_STOP_PLAYBACK, API_RESULT), | ||
100 | API_ENTRY(CX2341X_DEC_SET_PLAYBACK_SPEED, API_RESULT), | ||
101 | API_ENTRY(CX2341X_DEC_STEP_VIDEO, API_RESULT), | ||
102 | API_ENTRY(CX2341X_DEC_SET_DMA_BLOCK_SIZE, API_CACHE), | ||
103 | API_ENTRY(CX2341X_DEC_GET_XFER_INFO, API_FAST_RESULT), | ||
104 | API_ENTRY(CX2341X_DEC_GET_DMA_STATUS, API_FAST_RESULT), | ||
105 | API_ENTRY(CX2341X_DEC_SCHED_DMA_FROM_HOST, API_DMA), | ||
106 | API_ENTRY(CX2341X_DEC_PAUSE_PLAYBACK, API_RESULT), | ||
107 | API_ENTRY(CX2341X_DEC_HALT_FW, API_FAST_RESULT), | ||
108 | API_ENTRY(CX2341X_DEC_SET_STANDARD, API_CACHE), | ||
109 | API_ENTRY(CX2341X_DEC_GET_VERSION, API_FAST_RESULT), | ||
110 | API_ENTRY(CX2341X_DEC_SET_STREAM_INPUT, API_CACHE), | ||
111 | API_ENTRY(CX2341X_DEC_GET_TIMING_INFO, API_RESULT /*| API_NO_WAIT_RES*/), | ||
112 | API_ENTRY(CX2341X_DEC_SET_AUDIO_MODE, API_CACHE), | ||
113 | API_ENTRY(CX2341X_DEC_SET_EVENT_NOTIFICATION, API_RESULT), | ||
114 | API_ENTRY(CX2341X_DEC_SET_DISPLAY_BUFFERS, API_CACHE), | ||
115 | API_ENTRY(CX2341X_DEC_EXTRACT_VBI, API_RESULT), | ||
116 | API_ENTRY(CX2341X_DEC_SET_DECODER_SOURCE, API_FAST_RESULT), | ||
117 | API_ENTRY(CX2341X_DEC_SET_PREBUFFERING, API_CACHE), | ||
118 | |||
119 | /* OSD API */ | ||
120 | API_ENTRY(CX2341X_OSD_GET_FRAMEBUFFER, API_FAST_RESULT), | ||
121 | API_ENTRY(CX2341X_OSD_GET_PIXEL_FORMAT, API_FAST_RESULT), | ||
122 | API_ENTRY(CX2341X_OSD_SET_PIXEL_FORMAT, API_CACHE), | ||
123 | API_ENTRY(CX2341X_OSD_GET_STATE, API_FAST_RESULT), | ||
124 | API_ENTRY(CX2341X_OSD_SET_STATE, API_CACHE), | ||
125 | API_ENTRY(CX2341X_OSD_GET_OSD_COORDS, API_FAST_RESULT), | ||
126 | API_ENTRY(CX2341X_OSD_SET_OSD_COORDS, API_CACHE), | ||
127 | API_ENTRY(CX2341X_OSD_GET_SCREEN_COORDS, API_FAST_RESULT), | ||
128 | API_ENTRY(CX2341X_OSD_SET_SCREEN_COORDS, API_CACHE), | ||
129 | API_ENTRY(CX2341X_OSD_GET_GLOBAL_ALPHA, API_FAST_RESULT), | ||
130 | API_ENTRY(CX2341X_OSD_SET_GLOBAL_ALPHA, API_CACHE), | ||
131 | API_ENTRY(CX2341X_OSD_SET_BLEND_COORDS, API_CACHE), | ||
132 | API_ENTRY(CX2341X_OSD_GET_FLICKER_STATE, API_FAST_RESULT), | ||
133 | API_ENTRY(CX2341X_OSD_SET_FLICKER_STATE, API_CACHE), | ||
134 | API_ENTRY(CX2341X_OSD_BLT_COPY, API_RESULT), | ||
135 | API_ENTRY(CX2341X_OSD_BLT_FILL, API_RESULT), | ||
136 | API_ENTRY(CX2341X_OSD_BLT_TEXT, API_RESULT), | ||
137 | API_ENTRY(CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, API_CACHE), | ||
138 | API_ENTRY(CX2341X_OSD_SET_CHROMA_KEY, API_CACHE), | ||
139 | API_ENTRY(CX2341X_OSD_GET_ALPHA_CONTENT_INDEX, API_FAST_RESULT), | ||
140 | API_ENTRY(CX2341X_OSD_SET_ALPHA_CONTENT_INDEX, API_CACHE) | ||
141 | }; | ||
142 | |||
143 | static int try_mailbox(struct ivtv *itv, struct ivtv_mailbox_data *mbdata, int mb) | ||
144 | { | ||
145 | u32 flags = readl(&mbdata->mbox[mb].flags); | ||
146 | int is_free = flags == IVTV_MBOX_FREE || (flags & IVTV_MBOX_FIRMWARE_DONE); | ||
147 | |||
148 | /* if the mailbox is free, then try to claim it */ | ||
149 | if (is_free && !test_and_set_bit(mb, &mbdata->busy)) { | ||
150 | write_sync(IVTV_MBOX_DRIVER_BUSY, &mbdata->mbox[mb].flags); | ||
151 | return 1; | ||
152 | } | ||
153 | return 0; | ||
154 | } | ||
155 | |||
156 | /* Try to find a free mailbox. Note mailbox 0 is reserved for DMA and so is not | ||
157 | attempted here. */ | ||
158 | static int get_mailbox(struct ivtv *itv, struct ivtv_mailbox_data *mbdata, int flags) | ||
159 | { | ||
160 | unsigned long then = jiffies; | ||
161 | int i, mb; | ||
162 | int max_mbox = mbdata->max_mbox; | ||
163 | int retries = 100; | ||
164 | |||
165 | /* All slow commands use the same mailbox, serializing them and also | ||
166 | leaving the other mailbox free for simple fast commands. */ | ||
167 | if ((flags & API_FAST_RESULT) == API_RESULT) | ||
168 | max_mbox = 1; | ||
169 | |||
170 | /* find free non-DMA mailbox */ | ||
171 | for (i = 0; i < retries; i++) { | ||
172 | for (mb = 1; mb <= max_mbox; mb++) | ||
173 | if (try_mailbox(itv, mbdata, mb)) | ||
174 | return mb; | ||
175 | |||
176 | /* Sleep before a retry, if not atomic */ | ||
177 | if (!(flags & API_NO_WAIT_MB)) { | ||
178 | if (jiffies - then > retries * HZ / 100) | ||
179 | break; | ||
180 | ivtv_sleep_timeout(HZ / 100, 0); | ||
181 | } | ||
182 | } | ||
183 | return -ENODEV; | ||
184 | } | ||
185 | |||
186 | static void write_mailbox(volatile struct ivtv_mailbox __iomem *mbox, int cmd, int args, u32 data[]) | ||
187 | { | ||
188 | int i; | ||
189 | |||
190 | write_sync(cmd, &mbox->cmd); | ||
191 | write_sync(IVTV_API_STD_TIMEOUT, &mbox->timeout); | ||
192 | |||
193 | for (i = 0; i < CX2341X_MBOX_MAX_DATA; i++) | ||
194 | write_sync(data[i], &mbox->data[i]); | ||
195 | |||
196 | write_sync(IVTV_MBOX_DRIVER_DONE | IVTV_MBOX_DRIVER_BUSY, &mbox->flags); | ||
197 | } | ||
198 | |||
199 | static void clear_all_mailboxes(struct ivtv *itv, struct ivtv_mailbox_data *mbdata) | ||
200 | { | ||
201 | int i; | ||
202 | |||
203 | for (i = 0; i <= mbdata->max_mbox; i++) { | ||
204 | IVTV_DEBUG_WARN("Clearing mailbox %d: cmd 0x%08x flags 0x%08x\n", | ||
205 | i, readl(&mbdata->mbox[i].cmd), readl(&mbdata->mbox[i].flags)); | ||
206 | write_sync(0, &mbdata->mbox[i].flags); | ||
207 | clear_bit(i, &mbdata->busy); | ||
208 | } | ||
209 | } | ||
210 | |||
211 | static int ivtv_api_call(struct ivtv *itv, int cmd, int args, u32 data[]) | ||
212 | { | ||
213 | struct ivtv_mailbox_data *mbdata = (cmd >= 128) ? &itv->enc_mbox : &itv->dec_mbox; | ||
214 | volatile struct ivtv_mailbox __iomem *mbox; | ||
215 | int api_timeout = HZ; | ||
216 | int flags, mb, i; | ||
217 | unsigned long then; | ||
218 | |||
219 | /* sanity checks */ | ||
220 | if (NULL == mbdata) { | ||
221 | IVTV_ERR("No mailbox allocated\n"); | ||
222 | return -ENODEV; | ||
223 | } | ||
224 | if (args < 0 || args > CX2341X_MBOX_MAX_DATA || | ||
225 | cmd < 0 || cmd > 255 || api_info[cmd].name == NULL) { | ||
226 | IVTV_ERR("Invalid API call: cmd = 0x%02x, args = %d\n", cmd, args); | ||
227 | return -EINVAL; | ||
228 | } | ||
229 | |||
230 | IVTV_DEBUG_API("API Call: %s\n", api_info[cmd].name); | ||
231 | |||
232 | /* clear possibly uninitialized part of data array */ | ||
233 | for (i = args; i < CX2341X_MBOX_MAX_DATA; i++) | ||
234 | data[i] = 0; | ||
235 | |||
236 | /* If this command was issued within the last 30 minutes and with identical | ||
237 | data, then just return 0 as there is no need to issue this command again. | ||
238 | Just an optimization to prevent unnecessary use of mailboxes. */ | ||
239 | if (itv->api_cache[cmd].last_jiffies && | ||
240 | jiffies - itv->api_cache[cmd].last_jiffies < HZ * 1800 && | ||
241 | !memcmp(data, itv->api_cache[cmd].data, sizeof(itv->api_cache[cmd].data))) { | ||
242 | itv->api_cache[cmd].last_jiffies = jiffies; | ||
243 | return 0; | ||
244 | } | ||
245 | |||
246 | flags = api_info[cmd].flags; | ||
247 | |||
248 | if (flags & API_DMA) { | ||
249 | for (i = 0; i < 100; i++) { | ||
250 | mb = i % (mbdata->max_mbox + 1); | ||
251 | if (try_mailbox(itv, mbdata, mb)) { | ||
252 | write_mailbox(&mbdata->mbox[mb], cmd, args, data); | ||
253 | clear_bit(mb, &mbdata->busy); | ||
254 | return 0; | ||
255 | } | ||
256 | IVTV_DEBUG_WARN("%s: mailbox %d not free %08x\n", | ||
257 | api_info[cmd].name, mb, readl(&mbdata->mbox[mb].flags)); | ||
258 | } | ||
259 | IVTV_WARN("Could not find free DMA mailbox for %s\n", api_info[cmd].name); | ||
260 | clear_all_mailboxes(itv, mbdata); | ||
261 | return -EBUSY; | ||
262 | } | ||
263 | |||
264 | if ((flags & API_FAST_RESULT) == API_FAST_RESULT) | ||
265 | api_timeout = HZ / 10; | ||
266 | |||
267 | mb = get_mailbox(itv, mbdata, flags); | ||
268 | if (mb < 0) { | ||
269 | IVTV_DEBUG_WARN("No free mailbox found (%s)\n", api_info[cmd].name); | ||
270 | clear_all_mailboxes(itv, mbdata); | ||
271 | return -EBUSY; | ||
272 | } | ||
273 | mbox = &mbdata->mbox[mb]; | ||
274 | write_mailbox(mbox, cmd, args, data); | ||
275 | if (flags & API_CACHE) { | ||
276 | memcpy(itv->api_cache[cmd].data, data, sizeof(itv->api_cache[cmd].data)); | ||
277 | itv->api_cache[cmd].last_jiffies = jiffies; | ||
278 | } | ||
279 | if ((flags & API_RESULT) == 0) { | ||
280 | clear_bit(mb, &mbdata->busy); | ||
281 | return 0; | ||
282 | } | ||
283 | |||
284 | /* Get results */ | ||
285 | then = jiffies; | ||
286 | |||
287 | while (!(readl(&mbox->flags) & IVTV_MBOX_FIRMWARE_DONE)) { | ||
288 | if (jiffies - then > api_timeout) { | ||
289 | IVTV_DEBUG_WARN("Could not get result (%s)\n", api_info[cmd].name); | ||
290 | /* reset the mailbox, but it is likely too late already */ | ||
291 | write_sync(0, &mbox->flags); | ||
292 | clear_bit(mb, &mbdata->busy); | ||
293 | return -EIO; | ||
294 | } | ||
295 | if (flags & API_NO_WAIT_RES) | ||
296 | mdelay(1); | ||
297 | else | ||
298 | ivtv_sleep_timeout(HZ / 100, 0); | ||
299 | } | ||
300 | if (jiffies - then > HZ / 10) | ||
301 | IVTV_DEBUG_WARN("%s took %lu jiffies (%d per HZ)\n", | ||
302 | api_info[cmd].name, jiffies - then, HZ); | ||
303 | |||
304 | for (i = 0; i < CX2341X_MBOX_MAX_DATA; i++) | ||
305 | data[i] = readl(&mbox->data[i]); | ||
306 | write_sync(0, &mbox->flags); | ||
307 | clear_bit(mb, &mbdata->busy); | ||
308 | return 0; | ||
309 | } | ||
310 | |||
311 | int ivtv_api(struct ivtv *itv, int cmd, int args, u32 data[]) | ||
312 | { | ||
313 | int res = ivtv_api_call(itv, cmd, args, data); | ||
314 | |||
315 | /* Allow a single retry, probably already too late though. | ||
316 | If there is no free mailbox then that is usually an indication | ||
317 | of a more serious problem. */ | ||
318 | return (res == -EBUSY) ? ivtv_api_call(itv, cmd, args, data) : res; | ||
319 | } | ||
320 | |||
321 | int ivtv_api_func(void *priv, int cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]) | ||
322 | { | ||
323 | return ivtv_api(priv, cmd, in, data); | ||
324 | } | ||
325 | |||
326 | int ivtv_vapi_result(struct ivtv *itv, u32 data[CX2341X_MBOX_MAX_DATA], int cmd, int args, ...) | ||
327 | { | ||
328 | va_list ap; | ||
329 | int i; | ||
330 | |||
331 | va_start(ap, args); | ||
332 | for (i = 0; i < args; i++) { | ||
333 | data[i] = va_arg(ap, u32); | ||
334 | } | ||
335 | va_end(ap); | ||
336 | return ivtv_api(itv, cmd, args, data); | ||
337 | } | ||
338 | |||
339 | int ivtv_vapi(struct ivtv *itv, int cmd, int args, ...) | ||
340 | { | ||
341 | u32 data[CX2341X_MBOX_MAX_DATA]; | ||
342 | va_list ap; | ||
343 | int i; | ||
344 | |||
345 | va_start(ap, args); | ||
346 | for (i = 0; i < args; i++) { | ||
347 | data[i] = va_arg(ap, u32); | ||
348 | } | ||
349 | va_end(ap); | ||
350 | return ivtv_api(itv, cmd, args, data); | ||
351 | } | ||
352 | |||
353 | /* This one is for stuff that can't sleep.. irq handlers, etc.. */ | ||
354 | void ivtv_api_get_data(struct ivtv_mailbox_data *mbdata, int mb, u32 data[]) | ||
355 | { | ||
356 | int i; | ||
357 | |||
358 | for (i = 0; i < CX2341X_MBOX_MAX_DATA; i++) | ||
359 | data[i] = readl(&mbdata->mbox[mb].data[i]); | ||
360 | } | ||
diff --git a/drivers/media/video/ivtv/ivtv-mailbox.h b/drivers/media/video/ivtv/ivtv-mailbox.h new file mode 100644 index 000000000000..79b8aec14370 --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-mailbox.h | |||
@@ -0,0 +1,25 @@ | |||
1 | /* | ||
2 | mailbox functions | ||
3 | Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> | ||
4 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | void ivtv_api_get_data(struct ivtv_mailbox_data *mbox, int mb, u32 data[]); | ||
22 | int ivtv_api(struct ivtv *itv, int cmd, int args, u32 data[]); | ||
23 | int ivtv_vapi_result(struct ivtv *itv, u32 data[CX2341X_MBOX_MAX_DATA], int cmd, int args, ...); | ||
24 | int ivtv_vapi(struct ivtv *itv, int cmd, int args, ...); | ||
25 | int ivtv_api_func(void *priv, int cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]); | ||
diff --git a/drivers/media/video/ivtv/ivtv-queue.c b/drivers/media/video/ivtv/ivtv-queue.c new file mode 100644 index 000000000000..ccfcef1ad91a --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-queue.c | |||
@@ -0,0 +1,262 @@ | |||
1 | /* | ||
2 | buffer queues. | ||
3 | Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> | ||
4 | Copyright (C) 2004 Chris Kennedy <c@groovy.org> | ||
5 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2 of the License, or | ||
10 | (at your option) any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; if not, write to the Free Software | ||
19 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | */ | ||
21 | |||
22 | #include "ivtv-driver.h" | ||
23 | #include "ivtv-streams.h" | ||
24 | #include "ivtv-queue.h" | ||
25 | #include "ivtv-mailbox.h" | ||
26 | |||
27 | int ivtv_buf_copy_from_user(struct ivtv_stream *s, struct ivtv_buffer *buf, const char __user *src, int copybytes) | ||
28 | { | ||
29 | if (s->buf_size - buf->bytesused < copybytes) | ||
30 | copybytes = s->buf_size - buf->bytesused; | ||
31 | if (copy_from_user(buf->buf + buf->bytesused, src, copybytes)) { | ||
32 | return -EFAULT; | ||
33 | } | ||
34 | buf->bytesused += copybytes; | ||
35 | return copybytes; | ||
36 | } | ||
37 | |||
38 | void ivtv_buf_swap(struct ivtv_buffer *buf) | ||
39 | { | ||
40 | int i; | ||
41 | |||
42 | for (i = 0; i < buf->bytesused; i += 4) | ||
43 | swab32s((u32 *)(buf->buf + i)); | ||
44 | } | ||
45 | |||
46 | void ivtv_queue_init(struct ivtv_queue *q) | ||
47 | { | ||
48 | INIT_LIST_HEAD(&q->list); | ||
49 | q->buffers = 0; | ||
50 | q->length = 0; | ||
51 | q->bytesused = 0; | ||
52 | } | ||
53 | |||
54 | void ivtv_enqueue(struct ivtv_stream *s, struct ivtv_buffer *buf, struct ivtv_queue *q) | ||
55 | { | ||
56 | unsigned long flags = 0; | ||
57 | |||
58 | /* clear the buffer if it is going to be enqueued to the free queue */ | ||
59 | if (q == &s->q_free) { | ||
60 | buf->bytesused = 0; | ||
61 | buf->readpos = 0; | ||
62 | buf->b_flags = 0; | ||
63 | } | ||
64 | spin_lock_irqsave(&s->qlock, flags); | ||
65 | list_add_tail(&buf->list, &q->list); | ||
66 | q->buffers++; | ||
67 | q->length += s->buf_size; | ||
68 | q->bytesused += buf->bytesused - buf->readpos; | ||
69 | spin_unlock_irqrestore(&s->qlock, flags); | ||
70 | } | ||
71 | |||
72 | struct ivtv_buffer *ivtv_dequeue(struct ivtv_stream *s, struct ivtv_queue *q) | ||
73 | { | ||
74 | struct ivtv_buffer *buf = NULL; | ||
75 | unsigned long flags = 0; | ||
76 | |||
77 | spin_lock_irqsave(&s->qlock, flags); | ||
78 | if (!list_empty(&q->list)) { | ||
79 | buf = list_entry(q->list.next, struct ivtv_buffer, list); | ||
80 | list_del_init(q->list.next); | ||
81 | q->buffers--; | ||
82 | q->length -= s->buf_size; | ||
83 | q->bytesused -= buf->bytesused - buf->readpos; | ||
84 | } | ||
85 | spin_unlock_irqrestore(&s->qlock, flags); | ||
86 | return buf; | ||
87 | } | ||
88 | |||
89 | static void ivtv_queue_move_buf(struct ivtv_stream *s, struct ivtv_queue *from, | ||
90 | struct ivtv_queue *to, int clear, int full) | ||
91 | { | ||
92 | struct ivtv_buffer *buf = list_entry(from->list.next, struct ivtv_buffer, list); | ||
93 | |||
94 | list_move_tail(from->list.next, &to->list); | ||
95 | from->buffers--; | ||
96 | from->length -= s->buf_size; | ||
97 | from->bytesused -= buf->bytesused - buf->readpos; | ||
98 | /* special handling for q_free */ | ||
99 | if (clear) | ||
100 | buf->bytesused = buf->readpos = buf->b_flags = 0; | ||
101 | else if (full) { | ||
102 | /* special handling for stolen buffers, assume | ||
103 | all bytes are used. */ | ||
104 | buf->bytesused = s->buf_size; | ||
105 | buf->readpos = buf->b_flags = 0; | ||
106 | } | ||
107 | to->buffers++; | ||
108 | to->length += s->buf_size; | ||
109 | to->bytesused += buf->bytesused - buf->readpos; | ||
110 | } | ||
111 | |||
112 | /* Move 'needed_bytes' worth of buffers from queue 'from' into queue 'to'. | ||
113 | If 'needed_bytes' == 0, then move all buffers from 'from' into 'to'. | ||
114 | If 'steal' != NULL, then buffers may also taken from that queue if | ||
115 | needed. | ||
116 | |||
117 | The buffer is automatically cleared if it goes to the free queue. It is | ||
118 | also cleared if buffers need to be taken from the 'steal' queue and | ||
119 | the 'from' queue is the free queue. | ||
120 | |||
121 | When 'from' is q_free, then needed_bytes is compared to the total | ||
122 | available buffer length, otherwise needed_bytes is compared to the | ||
123 | bytesused value. For the 'steal' queue the total available buffer | ||
124 | length is always used. | ||
125 | |||
126 | -ENOMEM is returned if the buffers could not be obtained, 0 if all | ||
127 | buffers where obtained from the 'from' list and if non-zero then | ||
128 | the number of stolen buffers is returned. */ | ||
129 | int ivtv_queue_move(struct ivtv_stream *s, struct ivtv_queue *from, struct ivtv_queue *steal, | ||
130 | struct ivtv_queue *to, int needed_bytes) | ||
131 | { | ||
132 | unsigned long flags; | ||
133 | int rc = 0; | ||
134 | int from_free = from == &s->q_free; | ||
135 | int to_free = to == &s->q_free; | ||
136 | int bytes_available; | ||
137 | |||
138 | spin_lock_irqsave(&s->qlock, flags); | ||
139 | if (needed_bytes == 0) { | ||
140 | from_free = 1; | ||
141 | needed_bytes = from->length; | ||
142 | } | ||
143 | |||
144 | bytes_available = from_free ? from->length : from->bytesused; | ||
145 | bytes_available += steal ? steal->length : 0; | ||
146 | |||
147 | if (bytes_available < needed_bytes) { | ||
148 | spin_unlock_irqrestore(&s->qlock, flags); | ||
149 | return -ENOMEM; | ||
150 | } | ||
151 | if (from_free) { | ||
152 | u32 old_length = to->length; | ||
153 | |||
154 | while (to->length - old_length < needed_bytes) { | ||
155 | if (list_empty(&from->list)) | ||
156 | from = steal; | ||
157 | if (from == steal) | ||
158 | rc++; /* keep track of 'stolen' buffers */ | ||
159 | ivtv_queue_move_buf(s, from, to, 1, 0); | ||
160 | } | ||
161 | } | ||
162 | else { | ||
163 | u32 old_bytesused = to->bytesused; | ||
164 | |||
165 | while (to->bytesused - old_bytesused < needed_bytes) { | ||
166 | if (list_empty(&from->list)) | ||
167 | from = steal; | ||
168 | if (from == steal) | ||
169 | rc++; /* keep track of 'stolen' buffers */ | ||
170 | ivtv_queue_move_buf(s, from, to, to_free, rc); | ||
171 | } | ||
172 | } | ||
173 | spin_unlock_irqrestore(&s->qlock, flags); | ||
174 | return rc; | ||
175 | } | ||
176 | |||
177 | void ivtv_flush_queues(struct ivtv_stream *s) | ||
178 | { | ||
179 | ivtv_queue_move(s, &s->q_io, NULL, &s->q_free, 0); | ||
180 | ivtv_queue_move(s, &s->q_full, NULL, &s->q_free, 0); | ||
181 | ivtv_queue_move(s, &s->q_dma, NULL, &s->q_free, 0); | ||
182 | ivtv_queue_move(s, &s->q_predma, NULL, &s->q_free, 0); | ||
183 | } | ||
184 | |||
185 | int ivtv_stream_alloc(struct ivtv_stream *s) | ||
186 | { | ||
187 | struct ivtv *itv = s->itv; | ||
188 | int SGsize = sizeof(struct ivtv_SG_element) * s->buffers; | ||
189 | int i; | ||
190 | |||
191 | if (s->buffers == 0) | ||
192 | return 0; | ||
193 | |||
194 | IVTV_DEBUG_INFO("Allocate %s%s stream: %d x %d buffers (%dkB total)\n", | ||
195 | s->dma != PCI_DMA_NONE ? "DMA " : "", | ||
196 | s->name, s->buffers, s->buf_size, s->buffers * s->buf_size / 1024); | ||
197 | |||
198 | /* Allocate DMA SG Arrays */ | ||
199 | if (s->dma != PCI_DMA_NONE) { | ||
200 | s->SGarray = (struct ivtv_SG_element *)kzalloc(SGsize, GFP_KERNEL); | ||
201 | if (s->SGarray == NULL) { | ||
202 | IVTV_ERR("Could not allocate SGarray for %s stream\n", s->name); | ||
203 | return -ENOMEM; | ||
204 | } | ||
205 | s->SG_length = 0; | ||
206 | s->SG_handle = pci_map_single(itv->dev, s->SGarray, SGsize, s->dma); | ||
207 | ivtv_stream_sync_for_cpu(s); | ||
208 | } | ||
209 | |||
210 | /* allocate stream buffers. Initially all buffers are in q_free. */ | ||
211 | for (i = 0; i < s->buffers; i++) { | ||
212 | struct ivtv_buffer *buf = kzalloc(sizeof(struct ivtv_buffer), GFP_KERNEL); | ||
213 | |||
214 | if (buf == NULL) | ||
215 | break; | ||
216 | buf->buf = kmalloc(s->buf_size + 256, GFP_KERNEL); | ||
217 | if (buf->buf == NULL) { | ||
218 | kfree(buf); | ||
219 | break; | ||
220 | } | ||
221 | INIT_LIST_HEAD(&buf->list); | ||
222 | if (s->dma != PCI_DMA_NONE) { | ||
223 | buf->dma_handle = pci_map_single(s->itv->dev, | ||
224 | buf->buf, s->buf_size + 256, s->dma); | ||
225 | ivtv_buf_sync_for_cpu(s, buf); | ||
226 | } | ||
227 | ivtv_enqueue(s, buf, &s->q_free); | ||
228 | } | ||
229 | if (i == s->buffers) | ||
230 | return 0; | ||
231 | IVTV_ERR("Couldn't allocate buffers for %s stream\n", s->name); | ||
232 | ivtv_stream_free(s); | ||
233 | return -ENOMEM; | ||
234 | } | ||
235 | |||
236 | void ivtv_stream_free(struct ivtv_stream *s) | ||
237 | { | ||
238 | struct ivtv_buffer *buf; | ||
239 | |||
240 | /* move all buffers to q_free */ | ||
241 | ivtv_flush_queues(s); | ||
242 | |||
243 | /* empty q_free */ | ||
244 | while ((buf = ivtv_dequeue(s, &s->q_free))) { | ||
245 | if (s->dma != PCI_DMA_NONE) | ||
246 | pci_unmap_single(s->itv->dev, buf->dma_handle, | ||
247 | s->buf_size + 256, s->dma); | ||
248 | kfree(buf->buf); | ||
249 | kfree(buf); | ||
250 | } | ||
251 | |||
252 | /* Free SG Array/Lists */ | ||
253 | if (s->SGarray != NULL) { | ||
254 | if (s->SG_handle != IVTV_DMA_UNMAPPED) { | ||
255 | pci_unmap_single(s->itv->dev, s->SG_handle, | ||
256 | sizeof(struct ivtv_SG_element) * s->buffers, PCI_DMA_TODEVICE); | ||
257 | s->SG_handle = IVTV_DMA_UNMAPPED; | ||
258 | } | ||
259 | s->SGarray = NULL; | ||
260 | s->SG_length = 0; | ||
261 | } | ||
262 | } | ||
diff --git a/drivers/media/video/ivtv/ivtv-queue.h b/drivers/media/video/ivtv/ivtv-queue.h new file mode 100644 index 000000000000..903edd4b4381 --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-queue.h | |||
@@ -0,0 +1,64 @@ | |||
1 | /* | ||
2 | buffer queues. | ||
3 | Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> | ||
4 | Copyright (C) 2004 Chris Kennedy <c@groovy.org> | ||
5 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2 of the License, or | ||
10 | (at your option) any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; if not, write to the Free Software | ||
19 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | */ | ||
21 | |||
22 | #define IVTV_DMA_UNMAPPED ((u32) -1) | ||
23 | |||
24 | /* ivtv_buffer utility functions */ | ||
25 | static inline void ivtv_buf_sync_for_cpu(struct ivtv_stream *s, struct ivtv_buffer *buf) | ||
26 | { | ||
27 | if (s->dma != PCI_DMA_NONE) | ||
28 | pci_dma_sync_single_for_cpu(s->itv->dev, buf->dma_handle, | ||
29 | s->buf_size + 256, s->dma); | ||
30 | } | ||
31 | |||
32 | static inline void ivtv_buf_sync_for_device(struct ivtv_stream *s, struct ivtv_buffer *buf) | ||
33 | { | ||
34 | if (s->dma != PCI_DMA_NONE) | ||
35 | pci_dma_sync_single_for_device(s->itv->dev, buf->dma_handle, | ||
36 | s->buf_size + 256, s->dma); | ||
37 | } | ||
38 | |||
39 | int ivtv_buf_copy_from_user(struct ivtv_stream *s, struct ivtv_buffer *buf, const char __user *src, int copybytes); | ||
40 | void ivtv_buf_swap(struct ivtv_buffer *buf); | ||
41 | |||
42 | /* ivtv_queue utility functions */ | ||
43 | void ivtv_queue_init(struct ivtv_queue *q); | ||
44 | void ivtv_enqueue(struct ivtv_stream *s, struct ivtv_buffer *buf, struct ivtv_queue *q); | ||
45 | struct ivtv_buffer *ivtv_dequeue(struct ivtv_stream *s, struct ivtv_queue *q); | ||
46 | int ivtv_queue_move(struct ivtv_stream *s, struct ivtv_queue *from, struct ivtv_queue *steal, | ||
47 | struct ivtv_queue *to, int needed_bytes); | ||
48 | void ivtv_flush_queues(struct ivtv_stream *s); | ||
49 | |||
50 | /* ivtv_stream utility functions */ | ||
51 | int ivtv_stream_alloc(struct ivtv_stream *s); | ||
52 | void ivtv_stream_free(struct ivtv_stream *s); | ||
53 | |||
54 | static inline void ivtv_stream_sync_for_cpu(struct ivtv_stream *s) | ||
55 | { | ||
56 | pci_dma_sync_single_for_cpu(s->itv->dev, s->SG_handle, | ||
57 | sizeof(struct ivtv_SG_element) * s->buffers, PCI_DMA_TODEVICE); | ||
58 | } | ||
59 | |||
60 | static inline void ivtv_stream_sync_for_device(struct ivtv_stream *s) | ||
61 | { | ||
62 | pci_dma_sync_single_for_device(s->itv->dev, s->SG_handle, | ||
63 | sizeof(struct ivtv_SG_element) * s->buffers, PCI_DMA_TODEVICE); | ||
64 | } | ||
diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c new file mode 100644 index 000000000000..01a41a844a30 --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-streams.c | |||
@@ -0,0 +1,977 @@ | |||
1 | /* | ||
2 | init/start/stop/exit stream functions | ||
3 | Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> | ||
4 | Copyright (C) 2004 Chris Kennedy <c@groovy.org> | ||
5 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2 of the License, or | ||
10 | (at your option) any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; if not, write to the Free Software | ||
19 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | */ | ||
21 | |||
22 | /* License: GPL | ||
23 | * Author: Kevin Thayer <nufan_wfk at yahoo dot com> | ||
24 | * | ||
25 | * This file will hold API related functions, both internal (firmware api) | ||
26 | * and external (v4l2, etc) | ||
27 | * | ||
28 | * ----- | ||
29 | * MPG600/MPG160 support by T.Adachi <tadachi@tadachi-net.com> | ||
30 | * and Takeru KOMORIYA<komoriya@paken.org> | ||
31 | * | ||
32 | * AVerMedia M179 GPIO info by Chris Pinkham <cpinkham@bc2va.org> | ||
33 | * using information provided by Jiun-Kuei Jung @ AVerMedia. | ||
34 | */ | ||
35 | |||
36 | #include "ivtv-driver.h" | ||
37 | #include "ivtv-fileops.h" | ||
38 | #include "ivtv-i2c.h" | ||
39 | #include "ivtv-queue.h" | ||
40 | #include "ivtv-mailbox.h" | ||
41 | #include "ivtv-audio.h" | ||
42 | #include "ivtv-video.h" | ||
43 | #include "ivtv-vbi.h" | ||
44 | #include "ivtv-ioctl.h" | ||
45 | #include "ivtv-irq.h" | ||
46 | #include "ivtv-streams.h" | ||
47 | #include "ivtv-cards.h" | ||
48 | |||
49 | static struct file_operations ivtv_v4l2_enc_fops = { | ||
50 | .owner = THIS_MODULE, | ||
51 | .read = ivtv_v4l2_read, | ||
52 | .write = ivtv_v4l2_write, | ||
53 | .open = ivtv_v4l2_open, | ||
54 | .ioctl = ivtv_v4l2_ioctl, | ||
55 | .release = ivtv_v4l2_close, | ||
56 | .poll = ivtv_v4l2_enc_poll, | ||
57 | }; | ||
58 | |||
59 | static struct file_operations ivtv_v4l2_dec_fops = { | ||
60 | .owner = THIS_MODULE, | ||
61 | .read = ivtv_v4l2_read, | ||
62 | .write = ivtv_v4l2_write, | ||
63 | .open = ivtv_v4l2_open, | ||
64 | .ioctl = ivtv_v4l2_ioctl, | ||
65 | .release = ivtv_v4l2_close, | ||
66 | .poll = ivtv_v4l2_dec_poll, | ||
67 | }; | ||
68 | |||
69 | static struct { | ||
70 | const char *name; | ||
71 | int vfl_type; | ||
72 | int minor_offset; | ||
73 | int dma, pio; | ||
74 | enum v4l2_buf_type buf_type; | ||
75 | struct file_operations *fops; | ||
76 | } ivtv_stream_info[] = { | ||
77 | { /* IVTV_ENC_STREAM_TYPE_MPG */ | ||
78 | "encoder MPEG", | ||
79 | VFL_TYPE_GRABBER, 0, | ||
80 | PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_VIDEO_CAPTURE, | ||
81 | &ivtv_v4l2_enc_fops | ||
82 | }, | ||
83 | { /* IVTV_ENC_STREAM_TYPE_YUV */ | ||
84 | "encoder YUV", | ||
85 | VFL_TYPE_GRABBER, IVTV_V4L2_ENC_YUV_OFFSET, | ||
86 | PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_VIDEO_CAPTURE, | ||
87 | &ivtv_v4l2_enc_fops | ||
88 | }, | ||
89 | { /* IVTV_ENC_STREAM_TYPE_VBI */ | ||
90 | "encoder VBI", | ||
91 | VFL_TYPE_VBI, 0, | ||
92 | PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_VBI_CAPTURE, | ||
93 | &ivtv_v4l2_enc_fops | ||
94 | }, | ||
95 | { /* IVTV_ENC_STREAM_TYPE_PCM */ | ||
96 | "encoder PCM audio", | ||
97 | VFL_TYPE_GRABBER, IVTV_V4L2_ENC_PCM_OFFSET, | ||
98 | PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_PRIVATE, | ||
99 | &ivtv_v4l2_enc_fops | ||
100 | }, | ||
101 | { /* IVTV_ENC_STREAM_TYPE_RAD */ | ||
102 | "encoder radio", | ||
103 | VFL_TYPE_RADIO, 0, | ||
104 | PCI_DMA_NONE, 1, V4L2_BUF_TYPE_PRIVATE, | ||
105 | &ivtv_v4l2_enc_fops | ||
106 | }, | ||
107 | { /* IVTV_DEC_STREAM_TYPE_MPG */ | ||
108 | "decoder MPEG", | ||
109 | VFL_TYPE_GRABBER, IVTV_V4L2_DEC_MPG_OFFSET, | ||
110 | PCI_DMA_TODEVICE, 0, V4L2_BUF_TYPE_VIDEO_OUTPUT, | ||
111 | &ivtv_v4l2_dec_fops | ||
112 | }, | ||
113 | { /* IVTV_DEC_STREAM_TYPE_VBI */ | ||
114 | "decoder VBI", | ||
115 | VFL_TYPE_VBI, IVTV_V4L2_DEC_VBI_OFFSET, | ||
116 | PCI_DMA_NONE, 1, V4L2_BUF_TYPE_VBI_CAPTURE, | ||
117 | &ivtv_v4l2_enc_fops | ||
118 | }, | ||
119 | { /* IVTV_DEC_STREAM_TYPE_VOUT */ | ||
120 | "decoder VOUT", | ||
121 | VFL_TYPE_VBI, IVTV_V4L2_DEC_VOUT_OFFSET, | ||
122 | PCI_DMA_NONE, 1, V4L2_BUF_TYPE_VBI_OUTPUT, | ||
123 | &ivtv_v4l2_dec_fops | ||
124 | }, | ||
125 | { /* IVTV_DEC_STREAM_TYPE_YUV */ | ||
126 | "decoder YUV", | ||
127 | VFL_TYPE_GRABBER, IVTV_V4L2_DEC_YUV_OFFSET, | ||
128 | PCI_DMA_TODEVICE, 0, V4L2_BUF_TYPE_VIDEO_OUTPUT, | ||
129 | &ivtv_v4l2_dec_fops | ||
130 | } | ||
131 | }; | ||
132 | |||
133 | static void ivtv_stream_init(struct ivtv *itv, int type) | ||
134 | { | ||
135 | struct ivtv_stream *s = &itv->streams[type]; | ||
136 | struct video_device *dev = s->v4l2dev; | ||
137 | |||
138 | /* we need to keep v4l2dev, so restore it afterwards */ | ||
139 | memset(s, 0, sizeof(*s)); | ||
140 | s->v4l2dev = dev; | ||
141 | |||
142 | /* initialize ivtv_stream fields */ | ||
143 | s->itv = itv; | ||
144 | s->type = type; | ||
145 | s->name = ivtv_stream_info[type].name; | ||
146 | |||
147 | if (ivtv_stream_info[type].pio) | ||
148 | s->dma = PCI_DMA_NONE; | ||
149 | else | ||
150 | s->dma = ivtv_stream_info[type].dma; | ||
151 | s->buf_size = itv->stream_buf_size[type]; | ||
152 | if (s->buf_size) | ||
153 | s->buffers = itv->options.megabytes[type] * 1024 * 1024 / s->buf_size; | ||
154 | spin_lock_init(&s->qlock); | ||
155 | init_waitqueue_head(&s->waitq); | ||
156 | s->id = -1; | ||
157 | s->SG_handle = IVTV_DMA_UNMAPPED; | ||
158 | ivtv_queue_init(&s->q_free); | ||
159 | ivtv_queue_init(&s->q_full); | ||
160 | ivtv_queue_init(&s->q_dma); | ||
161 | ivtv_queue_init(&s->q_predma); | ||
162 | ivtv_queue_init(&s->q_io); | ||
163 | } | ||
164 | |||
165 | static int ivtv_reg_dev(struct ivtv *itv, int type) | ||
166 | { | ||
167 | struct ivtv_stream *s = &itv->streams[type]; | ||
168 | int vfl_type = ivtv_stream_info[type].vfl_type; | ||
169 | int minor_offset = ivtv_stream_info[type].minor_offset; | ||
170 | int minor; | ||
171 | |||
172 | /* These four fields are always initialized. If v4l2dev == NULL, then | ||
173 | this stream is not in use. In that case no other fields but these | ||
174 | four can be used. */ | ||
175 | s->v4l2dev = NULL; | ||
176 | s->itv = itv; | ||
177 | s->type = type; | ||
178 | s->name = ivtv_stream_info[type].name; | ||
179 | |||
180 | /* Check whether the radio is supported */ | ||
181 | if (type == IVTV_ENC_STREAM_TYPE_RAD && !(itv->v4l2_cap & V4L2_CAP_RADIO)) | ||
182 | return 0; | ||
183 | if (type >= IVTV_DEC_STREAM_TYPE_MPG && !(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) | ||
184 | return 0; | ||
185 | |||
186 | if (minor_offset >= 0) | ||
187 | /* card number + user defined offset + device offset */ | ||
188 | minor = itv->num + ivtv_first_minor + minor_offset; | ||
189 | else | ||
190 | minor = -1; | ||
191 | |||
192 | /* User explicitly selected 0 buffers for these streams, so don't | ||
193 | create them. */ | ||
194 | if (minor >= 0 && ivtv_stream_info[type].dma != PCI_DMA_NONE && | ||
195 | itv->options.megabytes[type] == 0) { | ||
196 | IVTV_INFO("Disabled %s device\n", ivtv_stream_info[type].name); | ||
197 | return 0; | ||
198 | } | ||
199 | |||
200 | ivtv_stream_init(itv, type); | ||
201 | |||
202 | /* allocate and initialize the v4l2 video device structure */ | ||
203 | s->v4l2dev = video_device_alloc(); | ||
204 | if (s->v4l2dev == NULL) { | ||
205 | IVTV_ERR("Couldn't allocate v4l2 video_device for %s\n", s->name); | ||
206 | return -ENOMEM; | ||
207 | } | ||
208 | |||
209 | s->v4l2dev->type = VID_TYPE_CAPTURE | VID_TYPE_TUNER | VID_TYPE_TELETEXT | | ||
210 | VID_TYPE_CLIPPING | VID_TYPE_SCALES | VID_TYPE_MPEG_ENCODER; | ||
211 | if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) { | ||
212 | s->v4l2dev->type |= VID_TYPE_MPEG_DECODER; | ||
213 | } | ||
214 | snprintf(s->v4l2dev->name, sizeof(s->v4l2dev->name), "ivtv%d %s", | ||
215 | itv->num, s->name); | ||
216 | |||
217 | s->v4l2dev->minor = minor; | ||
218 | s->v4l2dev->dev = &itv->dev->dev; | ||
219 | s->v4l2dev->fops = ivtv_stream_info[type].fops; | ||
220 | s->v4l2dev->release = video_device_release; | ||
221 | |||
222 | if (minor >= 0) { | ||
223 | /* Register device. First try the desired minor, then any free one. */ | ||
224 | if (video_register_device(s->v4l2dev, vfl_type, minor) && | ||
225 | video_register_device(s->v4l2dev, vfl_type, -1)) { | ||
226 | IVTV_ERR("Couldn't register v4l2 device for %s minor %d\n", | ||
227 | s->name, minor); | ||
228 | video_device_release(s->v4l2dev); | ||
229 | s->v4l2dev = NULL; | ||
230 | return -ENOMEM; | ||
231 | } | ||
232 | } | ||
233 | else { | ||
234 | /* Don't register a 'hidden' stream (OSD) */ | ||
235 | IVTV_INFO("Created framebuffer stream for %s\n", s->name); | ||
236 | return 0; | ||
237 | } | ||
238 | |||
239 | switch (vfl_type) { | ||
240 | case VFL_TYPE_GRABBER: | ||
241 | IVTV_INFO("Registered device video%d for %s (%d MB)\n", | ||
242 | s->v4l2dev->minor, s->name, itv->options.megabytes[type]); | ||
243 | break; | ||
244 | case VFL_TYPE_RADIO: | ||
245 | IVTV_INFO("Registered device radio%d for %s\n", | ||
246 | s->v4l2dev->minor - MINOR_VFL_TYPE_RADIO_MIN, s->name); | ||
247 | break; | ||
248 | case VFL_TYPE_VBI: | ||
249 | if (itv->options.megabytes[type]) | ||
250 | IVTV_INFO("Registered device vbi%d for %s (%d MB)\n", | ||
251 | s->v4l2dev->minor - MINOR_VFL_TYPE_VBI_MIN, | ||
252 | s->name, itv->options.megabytes[type]); | ||
253 | else | ||
254 | IVTV_INFO("Registered device vbi%d for %s\n", | ||
255 | s->v4l2dev->minor - MINOR_VFL_TYPE_VBI_MIN, s->name); | ||
256 | break; | ||
257 | } | ||
258 | return 0; | ||
259 | } | ||
260 | |||
261 | /* Initialize v4l2 variables and register v4l2 devices */ | ||
262 | int ivtv_streams_setup(struct ivtv *itv) | ||
263 | { | ||
264 | int type; | ||
265 | |||
266 | /* Setup V4L2 Devices */ | ||
267 | for (type = 0; type < IVTV_MAX_STREAMS; type++) { | ||
268 | /* Register Device */ | ||
269 | if (ivtv_reg_dev(itv, type)) | ||
270 | break; | ||
271 | |||
272 | if (itv->streams[type].v4l2dev == NULL) | ||
273 | continue; | ||
274 | |||
275 | /* Allocate Stream */ | ||
276 | if (ivtv_stream_alloc(&itv->streams[type])) | ||
277 | break; | ||
278 | } | ||
279 | if (type == IVTV_MAX_STREAMS) { | ||
280 | return 0; | ||
281 | } | ||
282 | |||
283 | /* One or more streams could not be initialized. Clean 'em all up. */ | ||
284 | ivtv_streams_cleanup(itv); | ||
285 | return -ENOMEM; | ||
286 | } | ||
287 | |||
288 | /* Unregister v4l2 devices */ | ||
289 | void ivtv_streams_cleanup(struct ivtv *itv) | ||
290 | { | ||
291 | int type; | ||
292 | |||
293 | /* Teardown all streams */ | ||
294 | for (type = 0; type < IVTV_MAX_STREAMS; type++) { | ||
295 | struct video_device *vdev = itv->streams[type].v4l2dev; | ||
296 | |||
297 | itv->streams[type].v4l2dev = NULL; | ||
298 | if (vdev == NULL) | ||
299 | continue; | ||
300 | |||
301 | ivtv_stream_free(&itv->streams[type]); | ||
302 | /* Free Device */ | ||
303 | if (vdev->minor == -1) /* 'Hidden' never registered stream (OSD) */ | ||
304 | video_device_release(vdev); | ||
305 | else /* All others, just unregister. */ | ||
306 | video_unregister_device(vdev); | ||
307 | } | ||
308 | } | ||
309 | |||
310 | static void ivtv_vbi_setup(struct ivtv *itv) | ||
311 | { | ||
312 | int raw = itv->vbi.sliced_in->service_set == 0; | ||
313 | u32 data[CX2341X_MBOX_MAX_DATA]; | ||
314 | int lines; | ||
315 | int i; | ||
316 | |||
317 | /* If Embed then streamtype must be Program */ | ||
318 | /* TODO: should we really do this? */ | ||
319 | if (0 && !raw && itv->vbi.insert_mpeg) { | ||
320 | itv->params.stream_type = 0; | ||
321 | |||
322 | /* assign stream type */ | ||
323 | ivtv_vapi(itv, CX2341X_ENC_SET_STREAM_TYPE, 1, itv->params.stream_type); | ||
324 | } | ||
325 | |||
326 | /* Reset VBI */ | ||
327 | ivtv_vapi(itv, CX2341X_ENC_SET_VBI_LINE, 5, 0xffff , 0, 0, 0, 0); | ||
328 | |||
329 | if (itv->is_60hz) { | ||
330 | itv->vbi.count = 12; | ||
331 | itv->vbi.start[0] = 10; | ||
332 | itv->vbi.start[1] = 273; | ||
333 | } else { /* PAL/SECAM */ | ||
334 | itv->vbi.count = 18; | ||
335 | itv->vbi.start[0] = 6; | ||
336 | itv->vbi.start[1] = 318; | ||
337 | } | ||
338 | |||
339 | /* setup VBI registers */ | ||
340 | itv->video_dec_func(itv, VIDIOC_S_FMT, &itv->vbi.in); | ||
341 | |||
342 | /* determine number of lines and total number of VBI bytes. | ||
343 | A raw line takes 1443 bytes: 2 * 720 + 4 byte frame header - 1 | ||
344 | The '- 1' byte is probably an unused U or V byte. Or something... | ||
345 | A sliced line takes 51 bytes: 4 byte frame header, 4 byte internal | ||
346 | header, 42 data bytes + checksum (to be confirmed) */ | ||
347 | if (raw) { | ||
348 | lines = itv->vbi.count * 2; | ||
349 | } else { | ||
350 | lines = itv->is_60hz ? 24 : 38; | ||
351 | if (itv->is_60hz && (itv->hw_flags & IVTV_HW_CX25840)) | ||
352 | lines += 2; | ||
353 | } | ||
354 | |||
355 | itv->vbi.enc_size = lines * (raw ? itv->vbi.raw_size : itv->vbi.sliced_size); | ||
356 | |||
357 | /* Note: sliced vs raw flag doesn't seem to have any effect | ||
358 | TODO: check mode (0x02) value with older ivtv versions. */ | ||
359 | data[0] = raw | 0x02 | (0xbd << 8); | ||
360 | |||
361 | /* Every X number of frames a VBI interrupt arrives (frames as in 25 or 30 fps) */ | ||
362 | data[1] = 1; | ||
363 | /* The VBI frames are stored in a ringbuffer with this size (with a VBI frame as unit) */ | ||
364 | data[2] = raw ? 4 : 8; | ||
365 | /* The start/stop codes determine which VBI lines end up in the raw VBI data area. | ||
366 | The codes are from table 24 in the saa7115 datasheet. Each raw/sliced/video line | ||
367 | is framed with codes FF0000XX where XX is the SAV/EAV (Start/End of Active Video) | ||
368 | code. These values for raw VBI are obtained from a driver disassembly. The sliced | ||
369 | start/stop codes was deduced from this, but they do not appear in the driver. | ||
370 | Other code pairs that I found are: 0x250E6249/0x13545454 and 0x25256262/0x38137F54. | ||
371 | However, I have no idea what these values are for. */ | ||
372 | if (itv->hw_flags & IVTV_HW_CX25840) { | ||
373 | /* Setup VBI for the cx25840 digitizer */ | ||
374 | if (raw) { | ||
375 | data[3] = 0x20602060; | ||
376 | data[4] = 0x30703070; | ||
377 | } else { | ||
378 | data[3] = 0xB0F0B0F0; | ||
379 | data[4] = 0xA0E0A0E0; | ||
380 | } | ||
381 | /* Lines per frame */ | ||
382 | data[5] = lines; | ||
383 | /* bytes per line */ | ||
384 | data[6] = (raw ? itv->vbi.raw_size : itv->vbi.sliced_size); | ||
385 | } else { | ||
386 | /* Setup VBI for the saa7115 digitizer */ | ||
387 | if (raw) { | ||
388 | data[3] = 0x25256262; | ||
389 | data[4] = 0x387F7F7F; | ||
390 | } else { | ||
391 | data[3] = 0xABABECEC; | ||
392 | data[4] = 0xB6F1F1F1; | ||
393 | } | ||
394 | /* Lines per frame */ | ||
395 | data[5] = lines; | ||
396 | /* bytes per line */ | ||
397 | data[6] = itv->vbi.enc_size / lines; | ||
398 | } | ||
399 | |||
400 | IVTV_DEBUG_INFO( | ||
401 | "Setup VBI API header 0x%08x pkts %d buffs %d ln %d sz %d\n", | ||
402 | data[0], data[1], data[2], data[5], data[6]); | ||
403 | |||
404 | ivtv_api(itv, CX2341X_ENC_SET_VBI_CONFIG, 7, data); | ||
405 | |||
406 | /* returns the VBI encoder memory area. */ | ||
407 | itv->vbi.enc_start = data[2]; | ||
408 | itv->vbi.fpi = data[0]; | ||
409 | if (!itv->vbi.fpi) | ||
410 | itv->vbi.fpi = 1; | ||
411 | |||
412 | IVTV_DEBUG_INFO("Setup VBI start 0x%08x frames %d fpi %d lines 0x%08x\n", | ||
413 | itv->vbi.enc_start, data[1], itv->vbi.fpi, itv->digitizer); | ||
414 | |||
415 | /* select VBI lines. | ||
416 | Note that the sliced argument seems to have no effect. */ | ||
417 | for (i = 2; i <= 24; i++) { | ||
418 | int valid; | ||
419 | |||
420 | if (itv->is_60hz) { | ||
421 | valid = i >= 10 && i < 22; | ||
422 | } else { | ||
423 | valid = i >= 6 && i < 24; | ||
424 | } | ||
425 | ivtv_vapi(itv, CX2341X_ENC_SET_VBI_LINE, 5, i - 1, | ||
426 | valid, 0 , 0, 0); | ||
427 | ivtv_vapi(itv, CX2341X_ENC_SET_VBI_LINE, 5, (i - 1) | 0x80000000, | ||
428 | valid, 0, 0, 0); | ||
429 | } | ||
430 | |||
431 | /* Remaining VBI questions: | ||
432 | - Is it possible to select particular VBI lines only for inclusion in the MPEG | ||
433 | stream? Currently you can only get the first X lines. | ||
434 | - Is mixed raw and sliced VBI possible? | ||
435 | - What's the meaning of the raw/sliced flag? | ||
436 | - What's the meaning of params 2, 3 & 4 of the Select VBI command? */ | ||
437 | } | ||
438 | |||
439 | int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s) | ||
440 | { | ||
441 | u32 data[CX2341X_MBOX_MAX_DATA]; | ||
442 | struct ivtv *itv = s->itv; | ||
443 | int captype = 0, subtype = 0; | ||
444 | int enable_passthrough = 0; | ||
445 | |||
446 | if (s->v4l2dev == NULL) | ||
447 | return -EINVAL; | ||
448 | |||
449 | IVTV_DEBUG_INFO("Start encoder stream %s\n", s->name); | ||
450 | |||
451 | switch (s->type) { | ||
452 | case IVTV_ENC_STREAM_TYPE_MPG: | ||
453 | captype = 0; | ||
454 | subtype = 3; | ||
455 | |||
456 | /* Stop Passthrough */ | ||
457 | if (itv->output_mode == OUT_PASSTHROUGH) { | ||
458 | ivtv_passthrough_mode(itv, 0); | ||
459 | enable_passthrough = 1; | ||
460 | } | ||
461 | itv->mpg_data_received = itv->vbi_data_inserted = 0; | ||
462 | itv->dualwatch_jiffies = jiffies; | ||
463 | itv->dualwatch_stereo_mode = itv->params.audio_properties & 0x0300; | ||
464 | itv->search_pack_header = 0; | ||
465 | break; | ||
466 | |||
467 | case IVTV_ENC_STREAM_TYPE_YUV: | ||
468 | if (itv->output_mode == OUT_PASSTHROUGH) { | ||
469 | captype = 2; | ||
470 | subtype = 11; /* video+audio+decoder */ | ||
471 | break; | ||
472 | } | ||
473 | captype = 1; | ||
474 | subtype = 1; | ||
475 | break; | ||
476 | case IVTV_ENC_STREAM_TYPE_PCM: | ||
477 | captype = 1; | ||
478 | subtype = 2; | ||
479 | break; | ||
480 | case IVTV_ENC_STREAM_TYPE_VBI: | ||
481 | captype = 1; | ||
482 | subtype = 4; | ||
483 | |||
484 | itv->vbi.frame = 0; | ||
485 | itv->vbi.inserted_frame = 0; | ||
486 | memset(itv->vbi.sliced_mpeg_size, | ||
487 | 0, sizeof(itv->vbi.sliced_mpeg_size)); | ||
488 | break; | ||
489 | default: | ||
490 | return -EINVAL; | ||
491 | } | ||
492 | s->subtype = subtype; | ||
493 | s->buffers_stolen = 0; | ||
494 | |||
495 | /* mute/unmute video */ | ||
496 | ivtv_vapi(itv, CX2341X_ENC_MUTE_VIDEO, 1, test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ? 1 : 0); | ||
497 | |||
498 | /* Clear Streamoff flags in case left from last capture */ | ||
499 | clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags); | ||
500 | |||
501 | if (atomic_read(&itv->capturing) == 0) { | ||
502 | /* Always use frame based mode. Experiments have demonstrated that byte | ||
503 | stream based mode results in dropped frames and corruption. Not often, | ||
504 | but occasionally. Many thanks go to Leonard Orb who spent a lot of | ||
505 | effort and time trying to trace the cause of the drop outs. */ | ||
506 | /* 1 frame per DMA */ | ||
507 | /*ivtv_vapi(itv, CX2341X_ENC_SET_DMA_BLOCK_SIZE, 2, 128, 0); */ | ||
508 | ivtv_vapi(itv, CX2341X_ENC_SET_DMA_BLOCK_SIZE, 2, 1, 1); | ||
509 | |||
510 | /* Stuff from Windows, we don't know what it is */ | ||
511 | ivtv_vapi(itv, CX2341X_ENC_SET_VERT_CROP_LINE, 1, 0); | ||
512 | /* According to the docs, this should be correct. However, this is | ||
513 | untested. I don't dare enable this without having tested it. | ||
514 | Only very few old cards actually have this hardware combination. | ||
515 | ivtv_vapi(itv, CX2341X_ENC_SET_VERT_CROP_LINE, 1, | ||
516 | ((itv->hw_flags & IVTV_HW_SAA7114) && itv->is_60hz) ? 10001 : 0); | ||
517 | */ | ||
518 | ivtv_vapi(itv, CX2341X_ENC_MISC, 2, 3, !itv->has_cx23415); | ||
519 | ivtv_vapi(itv, CX2341X_ENC_MISC, 2, 8, 0); | ||
520 | ivtv_vapi(itv, CX2341X_ENC_MISC, 2, 4, 1); | ||
521 | ivtv_vapi(itv, CX2341X_ENC_MISC, 1, 12); | ||
522 | |||
523 | /* assign placeholder */ | ||
524 | ivtv_vapi(itv, CX2341X_ENC_SET_PLACEHOLDER, 12, | ||
525 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); | ||
526 | |||
527 | ivtv_vapi(itv, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, itv->digitizer, itv->digitizer); | ||
528 | |||
529 | /* Setup VBI */ | ||
530 | if (itv->v4l2_cap & V4L2_CAP_VBI_CAPTURE) { | ||
531 | ivtv_vbi_setup(itv); | ||
532 | } | ||
533 | |||
534 | /* assign program index info. Mask 7: select I/P/B, Num_req: 400 max */ | ||
535 | ivtv_vapi_result(itv, data, CX2341X_ENC_SET_PGM_INDEX_INFO, 2, 7, 400); | ||
536 | itv->pgm_info_offset = data[0]; | ||
537 | itv->pgm_info_num = data[1]; | ||
538 | itv->pgm_info_write_idx = 0; | ||
539 | itv->pgm_info_read_idx = 0; | ||
540 | |||
541 | IVTV_DEBUG_INFO("PGM Index at 0x%08x with %d elements\n", | ||
542 | itv->pgm_info_offset, itv->pgm_info_num); | ||
543 | |||
544 | /* Setup API for Stream */ | ||
545 | cx2341x_update(itv, ivtv_api_func, NULL, &itv->params); | ||
546 | } | ||
547 | |||
548 | /* Vsync Setup */ | ||
549 | if (itv->has_cx23415 && !test_and_set_bit(IVTV_F_I_DIG_RST, &itv->i_flags)) { | ||
550 | /* event notification (on) */ | ||
551 | ivtv_vapi(itv, CX2341X_ENC_SET_EVENT_NOTIFICATION, 4, 0, 1, IVTV_IRQ_ENC_VIM_RST, -1); | ||
552 | ivtv_clear_irq_mask(itv, IVTV_IRQ_ENC_VIM_RST); | ||
553 | } | ||
554 | |||
555 | if (atomic_read(&itv->capturing) == 0) { | ||
556 | /* Clear all Pending Interrupts */ | ||
557 | ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_CAPTURE); | ||
558 | |||
559 | clear_bit(IVTV_F_I_EOS, &itv->i_flags); | ||
560 | |||
561 | /* Initialize Digitizer for Capture */ | ||
562 | ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0); | ||
563 | |||
564 | ivtv_sleep_timeout(HZ / 10, 0); | ||
565 | } | ||
566 | |||
567 | /* begin_capture */ | ||
568 | if (ivtv_vapi(itv, CX2341X_ENC_START_CAPTURE, 2, captype, subtype)) | ||
569 | { | ||
570 | IVTV_DEBUG_WARN( "Error starting capture!\n"); | ||
571 | return -EINVAL; | ||
572 | } | ||
573 | |||
574 | /* Start Passthrough */ | ||
575 | if (enable_passthrough) { | ||
576 | ivtv_passthrough_mode(itv, 1); | ||
577 | } | ||
578 | |||
579 | if (s->type == IVTV_ENC_STREAM_TYPE_VBI) | ||
580 | ivtv_clear_irq_mask(itv, IVTV_IRQ_ENC_VBI_CAP); | ||
581 | else | ||
582 | ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_CAPTURE); | ||
583 | |||
584 | /* you're live! sit back and await interrupts :) */ | ||
585 | atomic_inc(&itv->capturing); | ||
586 | return 0; | ||
587 | } | ||
588 | |||
589 | static int ivtv_setup_v4l2_decode_stream(struct ivtv_stream *s) | ||
590 | { | ||
591 | u32 data[CX2341X_MBOX_MAX_DATA]; | ||
592 | struct ivtv *itv = s->itv; | ||
593 | int datatype; | ||
594 | |||
595 | if (s->v4l2dev == NULL) | ||
596 | return -EINVAL; | ||
597 | |||
598 | IVTV_DEBUG_INFO("Setting some initial decoder settings\n"); | ||
599 | |||
600 | /* disable VBI signals, if the MPEG stream contains VBI data, | ||
601 | then that data will be processed automatically for you. */ | ||
602 | ivtv_disable_vbi(itv); | ||
603 | |||
604 | /* set audio mode to left/stereo for dual/stereo mode. */ | ||
605 | ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode); | ||
606 | |||
607 | /* set number of internal decoder buffers */ | ||
608 | ivtv_vapi(itv, CX2341X_DEC_SET_DISPLAY_BUFFERS, 1, 0); | ||
609 | |||
610 | /* prebuffering */ | ||
611 | ivtv_vapi(itv, CX2341X_DEC_SET_PREBUFFERING, 1, 1); | ||
612 | |||
613 | /* extract from user packets */ | ||
614 | ivtv_vapi_result(itv, data, CX2341X_DEC_EXTRACT_VBI, 1, 1); | ||
615 | itv->vbi.dec_start = data[0]; | ||
616 | |||
617 | IVTV_DEBUG_INFO("Decoder VBI RE-Insert start 0x%08x size 0x%08x\n", | ||
618 | itv->vbi.dec_start, data[1]); | ||
619 | |||
620 | /* set decoder source settings */ | ||
621 | /* Data type: 0 = mpeg from host, | ||
622 | 1 = yuv from encoder, | ||
623 | 2 = yuv_from_host */ | ||
624 | switch (s->type) { | ||
625 | case IVTV_DEC_STREAM_TYPE_YUV: | ||
626 | datatype = itv->output_mode == OUT_PASSTHROUGH ? 1 : 2; | ||
627 | IVTV_DEBUG_INFO("Setup DEC YUV Stream data[0] = %d\n", datatype); | ||
628 | break; | ||
629 | case IVTV_DEC_STREAM_TYPE_MPG: | ||
630 | default: | ||
631 | datatype = 0; | ||
632 | break; | ||
633 | } | ||
634 | if (ivtv_vapi(itv, CX2341X_DEC_SET_DECODER_SOURCE, 4, datatype, | ||
635 | itv->params.width, itv->params.height, itv->params.audio_properties)) { | ||
636 | IVTV_DEBUG_WARN("COULDN'T INITIALIZE DECODER SOURCE\n"); | ||
637 | } | ||
638 | return 0; | ||
639 | } | ||
640 | |||
641 | int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset) | ||
642 | { | ||
643 | struct ivtv *itv = s->itv; | ||
644 | |||
645 | if (s->v4l2dev == NULL) | ||
646 | return -EINVAL; | ||
647 | |||
648 | if (test_and_set_bit(IVTV_F_S_STREAMING, &s->s_flags)) | ||
649 | return 0; /* already started */ | ||
650 | |||
651 | IVTV_DEBUG_INFO("Starting decode stream %s (gop_offset %d)\n", s->name, gop_offset); | ||
652 | |||
653 | /* Clear Streamoff */ | ||
654 | if (s->type == IVTV_DEC_STREAM_TYPE_YUV) { | ||
655 | /* Initialize Decoder */ | ||
656 | /* Reprogram Decoder YUV Buffers for YUV */ | ||
657 | write_reg(yuv_offset[0] >> 4, 0x82c); | ||
658 | write_reg((yuv_offset[0] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x830); | ||
659 | write_reg(yuv_offset[0] >> 4, 0x834); | ||
660 | write_reg((yuv_offset[0] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x838); | ||
661 | |||
662 | write_reg_sync(0x00000000 | (0x0c << 16) | (0x0b << 8), 0x2d24); | ||
663 | |||
664 | write_reg_sync(0x00108080, 0x2898); | ||
665 | /* Enable YUV decoder output */ | ||
666 | write_reg_sync(0x01, IVTV_REG_VDM); | ||
667 | } | ||
668 | |||
669 | ivtv_setup_v4l2_decode_stream(s); | ||
670 | |||
671 | /* set dma size to 65536 bytes */ | ||
672 | ivtv_vapi(itv, CX2341X_DEC_SET_DMA_BLOCK_SIZE, 1, 65536); | ||
673 | |||
674 | clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags); | ||
675 | |||
676 | /* Zero out decoder counters */ | ||
677 | writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_FIELD_DISPLAYED].data[0]); | ||
678 | writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_FIELD_DISPLAYED].data[1]); | ||
679 | writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_FIELD_DISPLAYED].data[2]); | ||
680 | writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_FIELD_DISPLAYED].data[3]); | ||
681 | writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[0]); | ||
682 | writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[1]); | ||
683 | writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[2]); | ||
684 | writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[3]); | ||
685 | |||
686 | /* turn on notification of dual/stereo mode change */ | ||
687 | ivtv_vapi(itv, CX2341X_DEC_SET_EVENT_NOTIFICATION, 4, 0, 1, IVTV_IRQ_DEC_AUD_MODE_CHG, -1); | ||
688 | |||
689 | /* start playback */ | ||
690 | ivtv_vapi(itv, CX2341X_DEC_START_PLAYBACK, 2, gop_offset, 0); | ||
691 | |||
692 | /* Clear the following Interrupt mask bits for decoding */ | ||
693 | ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_DECODE); | ||
694 | IVTV_DEBUG_IRQ("IRQ Mask is now: 0x%08x\n", itv->irqmask); | ||
695 | |||
696 | /* you're live! sit back and await interrupts :) */ | ||
697 | atomic_inc(&itv->decoding); | ||
698 | return 0; | ||
699 | } | ||
700 | |||
701 | void ivtv_stop_all_captures(struct ivtv *itv) | ||
702 | { | ||
703 | int i; | ||
704 | |||
705 | for (i = IVTV_MAX_STREAMS - 1; i >= 0; i--) { | ||
706 | struct ivtv_stream *s = &itv->streams[i]; | ||
707 | |||
708 | if (s->v4l2dev == NULL) | ||
709 | continue; | ||
710 | if (test_bit(IVTV_F_S_STREAMING, &s->s_flags)) { | ||
711 | ivtv_stop_v4l2_encode_stream(s, 0); | ||
712 | } | ||
713 | } | ||
714 | } | ||
715 | |||
716 | int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) | ||
717 | { | ||
718 | struct ivtv *itv = s->itv; | ||
719 | DECLARE_WAITQUEUE(wait, current); | ||
720 | int cap_type; | ||
721 | unsigned long then; | ||
722 | int stopmode; | ||
723 | u32 data[CX2341X_MBOX_MAX_DATA]; | ||
724 | |||
725 | if (s->v4l2dev == NULL) | ||
726 | return -EINVAL; | ||
727 | |||
728 | /* This function assumes that you are allowed to stop the capture | ||
729 | and that we are actually capturing */ | ||
730 | |||
731 | IVTV_DEBUG_INFO("Stop Capture\n"); | ||
732 | |||
733 | if (s->type == IVTV_DEC_STREAM_TYPE_VOUT) | ||
734 | return 0; | ||
735 | if (atomic_read(&itv->capturing) == 0) | ||
736 | return 0; | ||
737 | |||
738 | switch (s->type) { | ||
739 | case IVTV_ENC_STREAM_TYPE_YUV: | ||
740 | cap_type = 1; | ||
741 | break; | ||
742 | case IVTV_ENC_STREAM_TYPE_PCM: | ||
743 | cap_type = 1; | ||
744 | break; | ||
745 | case IVTV_ENC_STREAM_TYPE_VBI: | ||
746 | cap_type = 1; | ||
747 | break; | ||
748 | case IVTV_ENC_STREAM_TYPE_MPG: | ||
749 | default: | ||
750 | cap_type = 0; | ||
751 | break; | ||
752 | } | ||
753 | |||
754 | /* Stop Capture Mode */ | ||
755 | if (s->type == IVTV_ENC_STREAM_TYPE_MPG && gop_end) { | ||
756 | stopmode = 0; | ||
757 | } else { | ||
758 | stopmode = 1; | ||
759 | } | ||
760 | |||
761 | /* end_capture */ | ||
762 | /* when: 0 = end of GOP 1 = NOW!, type: 0 = mpeg, subtype: 3 = video+audio */ | ||
763 | ivtv_vapi(itv, CX2341X_ENC_STOP_CAPTURE, 3, stopmode, cap_type, s->subtype); | ||
764 | |||
765 | /* only run these if we're shutting down the last cap */ | ||
766 | if (atomic_read(&itv->capturing) - 1 == 0) { | ||
767 | /* event notification (off) */ | ||
768 | if (test_and_clear_bit(IVTV_F_I_DIG_RST, &itv->i_flags)) { | ||
769 | /* type: 0 = refresh */ | ||
770 | /* on/off: 0 = off, intr: 0x10000000, mbox_id: -1: none */ | ||
771 | ivtv_vapi(itv, CX2341X_ENC_SET_EVENT_NOTIFICATION, 4, 0, 0, IVTV_IRQ_ENC_VIM_RST, -1); | ||
772 | ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VIM_RST); | ||
773 | } | ||
774 | } | ||
775 | |||
776 | then = jiffies; | ||
777 | |||
778 | if (!test_bit(IVTV_F_S_PASSTHROUGH, &s->s_flags)) { | ||
779 | if (s->type == IVTV_ENC_STREAM_TYPE_MPG && gop_end) { | ||
780 | /* only run these if we're shutting down the last cap */ | ||
781 | unsigned long duration; | ||
782 | |||
783 | then = jiffies; | ||
784 | add_wait_queue(&itv->cap_w, &wait); | ||
785 | |||
786 | set_current_state(TASK_INTERRUPTIBLE); | ||
787 | |||
788 | /* wait 2s for EOS interrupt */ | ||
789 | while (!test_bit(IVTV_F_I_EOS, &itv->i_flags) && jiffies < then + 2 * HZ) { | ||
790 | schedule_timeout(HZ / 100); | ||
791 | } | ||
792 | |||
793 | /* To convert jiffies to ms, we must multiply by 1000 | ||
794 | * and divide by HZ. To avoid runtime division, we | ||
795 | * convert this to multiplication by 1000/HZ. | ||
796 | * Since integer division truncates, we get the best | ||
797 | * accuracy if we do a rounding calculation of the constant. | ||
798 | * Think of the case where HZ is 1024. | ||
799 | */ | ||
800 | duration = ((1000 + HZ / 2) / HZ) * (jiffies - then); | ||
801 | |||
802 | if (!test_bit(IVTV_F_I_EOS, &itv->i_flags)) { | ||
803 | IVTV_DEBUG_WARN("%s: EOS interrupt not received! stopping anyway.\n", s->name); | ||
804 | IVTV_DEBUG_WARN("%s: waited %lu ms.\n", s->name, duration); | ||
805 | } else { | ||
806 | IVTV_DEBUG_INFO("%s: EOS took %lu ms to occur.\n", s->name, duration); | ||
807 | } | ||
808 | set_current_state(TASK_RUNNING); | ||
809 | remove_wait_queue(&itv->cap_w, &wait); | ||
810 | } | ||
811 | |||
812 | then = jiffies; | ||
813 | /* Make sure DMA is complete */ | ||
814 | add_wait_queue(&s->waitq, &wait); | ||
815 | set_current_state(TASK_INTERRUPTIBLE); | ||
816 | do { | ||
817 | /* check if DMA is pending */ | ||
818 | if ((s->type == IVTV_ENC_STREAM_TYPE_MPG) && /* MPG Only */ | ||
819 | (read_reg(IVTV_REG_DMASTATUS) & 0x02)) { | ||
820 | /* Check for last DMA */ | ||
821 | ivtv_vapi_result(itv, data, CX2341X_ENC_GET_SEQ_END, 2, 0, 0); | ||
822 | |||
823 | if (data[0] == 1) { | ||
824 | IVTV_DEBUG_DMA("%s: Last DMA of size 0x%08x\n", s->name, data[1]); | ||
825 | break; | ||
826 | } | ||
827 | } else if (read_reg(IVTV_REG_DMASTATUS) & 0x02) { | ||
828 | break; | ||
829 | } | ||
830 | |||
831 | ivtv_sleep_timeout(HZ / 100, 1); | ||
832 | } while (then + HZ * 2 > jiffies); | ||
833 | |||
834 | set_current_state(TASK_RUNNING); | ||
835 | remove_wait_queue(&s->waitq, &wait); | ||
836 | } | ||
837 | |||
838 | atomic_dec(&itv->capturing); | ||
839 | |||
840 | /* Clear capture and no-read bits */ | ||
841 | clear_bit(IVTV_F_S_STREAMING, &s->s_flags); | ||
842 | |||
843 | if (s->type == IVTV_ENC_STREAM_TYPE_VBI) | ||
844 | ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VBI_CAP); | ||
845 | |||
846 | if (atomic_read(&itv->capturing) > 0) { | ||
847 | return 0; | ||
848 | } | ||
849 | |||
850 | /* Set the following Interrupt mask bits for capture */ | ||
851 | ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_CAPTURE); | ||
852 | |||
853 | wake_up(&s->waitq); | ||
854 | |||
855 | return 0; | ||
856 | } | ||
857 | |||
858 | int ivtv_stop_v4l2_decode_stream(struct ivtv_stream *s, int flags, u64 pts) | ||
859 | { | ||
860 | struct ivtv *itv = s->itv; | ||
861 | |||
862 | if (s->v4l2dev == NULL) | ||
863 | return -EINVAL; | ||
864 | |||
865 | if (s->type != IVTV_DEC_STREAM_TYPE_YUV && s->type != IVTV_DEC_STREAM_TYPE_MPG) | ||
866 | return -EINVAL; | ||
867 | |||
868 | if (!test_bit(IVTV_F_S_STREAMING, &s->s_flags)) | ||
869 | return 0; | ||
870 | |||
871 | IVTV_DEBUG_INFO("Stop Decode at %llu, flags: %x\n", pts, flags); | ||
872 | |||
873 | /* Stop Decoder */ | ||
874 | if (!(flags & VIDEO_CMD_STOP_IMMEDIATELY) || pts) { | ||
875 | u32 tmp = 0; | ||
876 | |||
877 | /* Wait until the decoder is no longer running */ | ||
878 | if (pts) { | ||
879 | ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 3, | ||
880 | 0, (u32)(pts & 0xffffffff), (u32)(pts >> 32)); | ||
881 | } | ||
882 | while (1) { | ||
883 | u32 data[CX2341X_MBOX_MAX_DATA]; | ||
884 | ivtv_vapi_result(itv, data, CX2341X_DEC_GET_XFER_INFO, 0); | ||
885 | if (s->q_full.buffers + s->q_dma.buffers == 0) { | ||
886 | if (tmp == data[3]) | ||
887 | break; | ||
888 | tmp = data[3]; | ||
889 | } | ||
890 | if (ivtv_sleep_timeout(HZ/10, 1)) | ||
891 | break; | ||
892 | } | ||
893 | } | ||
894 | ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 3, flags & VIDEO_CMD_STOP_TO_BLACK, 0, 0); | ||
895 | |||
896 | /* turn off notification of dual/stereo mode change */ | ||
897 | ivtv_vapi(itv, CX2341X_DEC_SET_EVENT_NOTIFICATION, 4, 0, 0, IVTV_IRQ_DEC_AUD_MODE_CHG, -1); | ||
898 | |||
899 | ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_DECODE); | ||
900 | |||
901 | clear_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags); | ||
902 | clear_bit(IVTV_F_S_STREAMING, &s->s_flags); | ||
903 | ivtv_flush_queues(s); | ||
904 | |||
905 | if (!test_bit(IVTV_F_S_PASSTHROUGH, &s->s_flags)) { | ||
906 | /* disable VBI on TV-out */ | ||
907 | ivtv_disable_vbi(itv); | ||
908 | } | ||
909 | |||
910 | /* decrement decoding */ | ||
911 | atomic_dec(&itv->decoding); | ||
912 | |||
913 | set_bit(IVTV_F_I_EV_DEC_STOPPED, &itv->i_flags); | ||
914 | wake_up(&itv->event_waitq); | ||
915 | |||
916 | /* wake up wait queues */ | ||
917 | wake_up(&s->waitq); | ||
918 | |||
919 | return 0; | ||
920 | } | ||
921 | |||
922 | int ivtv_passthrough_mode(struct ivtv *itv, int enable) | ||
923 | { | ||
924 | struct ivtv_stream *yuv_stream = &itv->streams[IVTV_ENC_STREAM_TYPE_YUV]; | ||
925 | struct ivtv_stream *dec_stream = &itv->streams[IVTV_DEC_STREAM_TYPE_YUV]; | ||
926 | |||
927 | if (yuv_stream->v4l2dev == NULL || dec_stream->v4l2dev == NULL) | ||
928 | return -EINVAL; | ||
929 | |||
930 | IVTV_DEBUG_INFO("ivtv ioctl: Select passthrough mode\n"); | ||
931 | |||
932 | /* Prevent others from starting/stopping streams while we | ||
933 | initiate/terminate passthrough mode */ | ||
934 | if (enable) { | ||
935 | if (itv->output_mode == OUT_PASSTHROUGH) { | ||
936 | return 0; | ||
937 | } | ||
938 | if (ivtv_set_output_mode(itv, OUT_PASSTHROUGH) != OUT_PASSTHROUGH) | ||
939 | return -EBUSY; | ||
940 | |||
941 | /* Fully initialize stream, and then unflag init */ | ||
942 | set_bit(IVTV_F_S_PASSTHROUGH, &dec_stream->s_flags); | ||
943 | set_bit(IVTV_F_S_STREAMING, &dec_stream->s_flags); | ||
944 | |||
945 | /* Setup YUV Decoder */ | ||
946 | ivtv_setup_v4l2_decode_stream(dec_stream); | ||
947 | |||
948 | /* Start Decoder */ | ||
949 | ivtv_vapi(itv, CX2341X_DEC_START_PLAYBACK, 2, 0, 1); | ||
950 | atomic_inc(&itv->decoding); | ||
951 | |||
952 | /* Setup capture if not already done */ | ||
953 | if (atomic_read(&itv->capturing) == 0) { | ||
954 | cx2341x_update(itv, ivtv_api_func, NULL, &itv->params); | ||
955 | } | ||
956 | |||
957 | /* Start Passthrough Mode */ | ||
958 | ivtv_vapi(itv, CX2341X_ENC_START_CAPTURE, 2, 2, 11); | ||
959 | atomic_inc(&itv->capturing); | ||
960 | return 0; | ||
961 | } | ||
962 | |||
963 | if (itv->output_mode != OUT_PASSTHROUGH) | ||
964 | return 0; | ||
965 | |||
966 | /* Stop Passthrough Mode */ | ||
967 | ivtv_vapi(itv, CX2341X_ENC_STOP_CAPTURE, 3, 1, 2, 11); | ||
968 | ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 3, 1, 0, 0); | ||
969 | |||
970 | atomic_dec(&itv->capturing); | ||
971 | atomic_dec(&itv->decoding); | ||
972 | clear_bit(IVTV_F_S_PASSTHROUGH, &dec_stream->s_flags); | ||
973 | clear_bit(IVTV_F_S_STREAMING, &dec_stream->s_flags); | ||
974 | itv->output_mode = OUT_NONE; | ||
975 | |||
976 | return 0; | ||
977 | } | ||
diff --git a/drivers/media/video/ivtv/ivtv-streams.h b/drivers/media/video/ivtv/ivtv-streams.h new file mode 100644 index 000000000000..8597b75384a7 --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-streams.h | |||
@@ -0,0 +1,31 @@ | |||
1 | /* | ||
2 | init/start/stop/exit stream functions | ||
3 | Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> | ||
4 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | int ivtv_streams_setup(struct ivtv *itv); | ||
22 | void ivtv_streams_cleanup(struct ivtv *itv); | ||
23 | |||
24 | /* Capture related */ | ||
25 | int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s); | ||
26 | int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end); | ||
27 | int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset); | ||
28 | int ivtv_stop_v4l2_decode_stream(struct ivtv_stream *s, int flags, u64 pts); | ||
29 | |||
30 | void ivtv_stop_all_captures(struct ivtv *itv); | ||
31 | int ivtv_passthrough_mode(struct ivtv *itv, int enable); | ||
diff --git a/drivers/media/video/ivtv/ivtv-udma.c b/drivers/media/video/ivtv/ivtv-udma.c new file mode 100644 index 000000000000..bd642e1aafc3 --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-udma.c | |||
@@ -0,0 +1,200 @@ | |||
1 | /* | ||
2 | User DMA | ||
3 | |||
4 | Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> | ||
5 | Copyright (C) 2004 Chris Kennedy <c@groovy.org> | ||
6 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
7 | |||
8 | This program is free software; you can redistribute it and/or modify | ||
9 | it under the terms of the GNU General Public License as published by | ||
10 | the Free Software Foundation; either version 2 of the License, or | ||
11 | (at your option) any later version. | ||
12 | |||
13 | This program is distributed in the hope that it will be useful, | ||
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | GNU General Public License for more details. | ||
17 | |||
18 | You should have received a copy of the GNU General Public License | ||
19 | along with this program; if not, write to the Free Software | ||
20 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
21 | */ | ||
22 | |||
23 | #include "ivtv-driver.h" | ||
24 | #include "ivtv-streams.h" | ||
25 | #include "ivtv-udma.h" | ||
26 | |||
27 | void ivtv_udma_get_page_info(struct ivtv_dma_page_info *dma_page, unsigned long first, unsigned long size) | ||
28 | { | ||
29 | dma_page->uaddr = first & PAGE_MASK; | ||
30 | dma_page->offset = first & ~PAGE_MASK; | ||
31 | dma_page->tail = 1 + ((first+size-1) & ~PAGE_MASK); | ||
32 | dma_page->first = (first & PAGE_MASK) >> PAGE_SHIFT; | ||
33 | dma_page->last = ((first+size-1) & PAGE_MASK) >> PAGE_SHIFT; | ||
34 | dma_page->page_count = dma_page->last - dma_page->first + 1; | ||
35 | if (dma_page->page_count == 1) dma_page->tail -= dma_page->offset; | ||
36 | } | ||
37 | |||
38 | int ivtv_udma_fill_sg_list (struct ivtv_user_dma *dma, struct ivtv_dma_page_info *dma_page, int map_offset) | ||
39 | { | ||
40 | int i, offset; | ||
41 | |||
42 | offset = dma_page->offset; | ||
43 | |||
44 | /* Fill SG Array with new values */ | ||
45 | for (i = 0; i < dma_page->page_count; i++) { | ||
46 | if (i == dma_page->page_count - 1) { | ||
47 | dma->SGlist[map_offset].length = dma_page->tail; | ||
48 | } | ||
49 | else { | ||
50 | dma->SGlist[map_offset].length = PAGE_SIZE - offset; | ||
51 | } | ||
52 | dma->SGlist[map_offset].offset = offset; | ||
53 | dma->SGlist[map_offset].page = dma->map[map_offset]; | ||
54 | offset = 0; | ||
55 | map_offset++; | ||
56 | } | ||
57 | return map_offset; | ||
58 | } | ||
59 | |||
60 | void ivtv_udma_fill_sg_array (struct ivtv_user_dma *dma, u32 buffer_offset, u32 buffer_offset_2, u32 split) { | ||
61 | int i; | ||
62 | struct scatterlist *sg; | ||
63 | |||
64 | for (i = 0, sg = dma->SGlist; i < dma->SG_length; i++, sg++) { | ||
65 | dma->SGarray[i].size = cpu_to_le32(sg_dma_len(sg)); | ||
66 | dma->SGarray[i].src = cpu_to_le32(sg_dma_address(sg)); | ||
67 | dma->SGarray[i].dst = cpu_to_le32(buffer_offset); | ||
68 | buffer_offset += sg_dma_len(sg); | ||
69 | |||
70 | split -= sg_dma_len(sg); | ||
71 | if (split == 0) | ||
72 | buffer_offset = buffer_offset_2; | ||
73 | } | ||
74 | } | ||
75 | |||
76 | /* User DMA Buffers */ | ||
77 | void ivtv_udma_alloc(struct ivtv *itv) | ||
78 | { | ||
79 | if (itv->udma.SG_handle == 0) { | ||
80 | /* Map DMA Page Array Buffer */ | ||
81 | itv->udma.SG_handle = pci_map_single(itv->dev, itv->udma.SGarray, | ||
82 | sizeof(itv->udma.SGarray), PCI_DMA_TODEVICE); | ||
83 | ivtv_udma_sync_for_cpu(itv); | ||
84 | } | ||
85 | } | ||
86 | |||
87 | int ivtv_udma_setup(struct ivtv *itv, unsigned long ivtv_dest_addr, | ||
88 | void __user *userbuf, int size_in_bytes) | ||
89 | { | ||
90 | struct ivtv_dma_page_info user_dma; | ||
91 | struct ivtv_user_dma *dma = &itv->udma; | ||
92 | int err; | ||
93 | |||
94 | IVTV_DEBUG_DMA("ivtv_udma_setup, dst: 0x%08x\n", (unsigned int)ivtv_dest_addr); | ||
95 | |||
96 | /* Still in USE */ | ||
97 | if (dma->SG_length || dma->page_count) { | ||
98 | IVTV_DEBUG_WARN("ivtv_udma_setup: SG_length %d page_count %d still full?\n", | ||
99 | dma->SG_length, dma->page_count); | ||
100 | return -EBUSY; | ||
101 | } | ||
102 | |||
103 | ivtv_udma_get_page_info(&user_dma, (unsigned long)userbuf, size_in_bytes); | ||
104 | |||
105 | if (user_dma.page_count <= 0) { | ||
106 | IVTV_DEBUG_WARN("ivtv_udma_setup: Error %d page_count from %d bytes %d offset\n", | ||
107 | user_dma.page_count, size_in_bytes, user_dma.offset); | ||
108 | return -EINVAL; | ||
109 | } | ||
110 | |||
111 | /* Get user pages for DMA Xfer */ | ||
112 | down_read(¤t->mm->mmap_sem); | ||
113 | err = get_user_pages(current, current->mm, | ||
114 | user_dma.uaddr, user_dma.page_count, 0, 1, dma->map, NULL); | ||
115 | up_read(¤t->mm->mmap_sem); | ||
116 | |||
117 | if (user_dma.page_count != err) { | ||
118 | IVTV_DEBUG_WARN("failed to map user pages, returned %d instead of %d\n", | ||
119 | err, user_dma.page_count); | ||
120 | return -EINVAL; | ||
121 | } | ||
122 | |||
123 | dma->page_count = user_dma.page_count; | ||
124 | |||
125 | /* Fill SG List with new values */ | ||
126 | ivtv_udma_fill_sg_list(dma, &user_dma, 0); | ||
127 | |||
128 | /* Map SG List */ | ||
129 | dma->SG_length = pci_map_sg(itv->dev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE); | ||
130 | |||
131 | /* Fill SG Array with new values */ | ||
132 | ivtv_udma_fill_sg_array (dma, ivtv_dest_addr, 0, -1); | ||
133 | |||
134 | /* Tag SG Array with Interrupt Bit */ | ||
135 | dma->SGarray[dma->SG_length - 1].size |= cpu_to_le32(0x80000000); | ||
136 | |||
137 | ivtv_udma_sync_for_device(itv); | ||
138 | return dma->page_count; | ||
139 | } | ||
140 | |||
141 | void ivtv_udma_unmap(struct ivtv *itv) | ||
142 | { | ||
143 | struct ivtv_user_dma *dma = &itv->udma; | ||
144 | int i; | ||
145 | |||
146 | IVTV_DEBUG_INFO("ivtv_unmap_user_dma\n"); | ||
147 | |||
148 | /* Nothing to free */ | ||
149 | if (dma->page_count == 0) | ||
150 | return; | ||
151 | |||
152 | /* Unmap Scatterlist */ | ||
153 | if (dma->SG_length) { | ||
154 | pci_unmap_sg(itv->dev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE); | ||
155 | dma->SG_length = 0; | ||
156 | } | ||
157 | /* sync DMA */ | ||
158 | ivtv_udma_sync_for_cpu(itv); | ||
159 | |||
160 | /* Release User Pages */ | ||
161 | for (i = 0; i < dma->page_count; i++) { | ||
162 | put_page(dma->map[i]); | ||
163 | } | ||
164 | dma->page_count = 0; | ||
165 | } | ||
166 | |||
167 | void ivtv_udma_free(struct ivtv *itv) | ||
168 | { | ||
169 | /* Unmap SG Array */ | ||
170 | if (itv->udma.SG_handle) { | ||
171 | pci_unmap_single(itv->dev, itv->udma.SG_handle, | ||
172 | sizeof(itv->udma.SGarray), PCI_DMA_TODEVICE); | ||
173 | } | ||
174 | |||
175 | /* Unmap Scatterlist */ | ||
176 | if (itv->udma.SG_length) { | ||
177 | pci_unmap_sg(itv->dev, itv->udma.SGlist, itv->udma.page_count, PCI_DMA_TODEVICE); | ||
178 | } | ||
179 | } | ||
180 | |||
181 | void ivtv_udma_start(struct ivtv *itv) | ||
182 | { | ||
183 | IVTV_DEBUG_DMA("start UDMA\n"); | ||
184 | write_reg(itv->udma.SG_handle, IVTV_REG_DECDMAADDR); | ||
185 | write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x01, IVTV_REG_DMAXFER); | ||
186 | set_bit(IVTV_F_I_DMA, &itv->i_flags); | ||
187 | set_bit(IVTV_F_I_UDMA, &itv->i_flags); | ||
188 | } | ||
189 | |||
190 | void ivtv_udma_prepare(struct ivtv *itv) | ||
191 | { | ||
192 | unsigned long flags; | ||
193 | |||
194 | spin_lock_irqsave(&itv->dma_reg_lock, flags); | ||
195 | if (!test_bit(IVTV_F_I_DMA, &itv->i_flags)) | ||
196 | ivtv_udma_start(itv); | ||
197 | else | ||
198 | set_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags); | ||
199 | spin_unlock_irqrestore(&itv->dma_reg_lock, flags); | ||
200 | } | ||
diff --git a/drivers/media/video/ivtv/ivtv-udma.h b/drivers/media/video/ivtv/ivtv-udma.h new file mode 100644 index 000000000000..e131bccedec0 --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-udma.h | |||
@@ -0,0 +1,43 @@ | |||
1 | /* | ||
2 | Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> | ||
3 | Copyright (C) 2004 Chris Kennedy <c@groovy.org> | ||
4 | Copyright (C) 2006-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | /* User DMA functions */ | ||
22 | void ivtv_udma_get_page_info(struct ivtv_dma_page_info *dma_page, unsigned long first, unsigned long size); | ||
23 | int ivtv_udma_fill_sg_list(struct ivtv_user_dma *dma, struct ivtv_dma_page_info *dma_page, int map_offset); | ||
24 | void ivtv_udma_fill_sg_array(struct ivtv_user_dma *dma, u32 buffer_offset, u32 buffer_offset_2, u32 split); | ||
25 | int ivtv_udma_setup(struct ivtv *itv, unsigned long ivtv_dest_addr, | ||
26 | void __user *userbuf, int size_in_bytes); | ||
27 | void ivtv_udma_unmap(struct ivtv *itv); | ||
28 | void ivtv_udma_free(struct ivtv *itv); | ||
29 | void ivtv_udma_alloc(struct ivtv *itv); | ||
30 | void ivtv_udma_prepare(struct ivtv *itv); | ||
31 | void ivtv_udma_start(struct ivtv *itv); | ||
32 | |||
33 | static inline void ivtv_udma_sync_for_device(struct ivtv *itv) | ||
34 | { | ||
35 | pci_dma_sync_single_for_device((struct pci_dev *)itv->dev, itv->udma.SG_handle, | ||
36 | sizeof(itv->udma.SGarray), PCI_DMA_TODEVICE); | ||
37 | } | ||
38 | |||
39 | static inline void ivtv_udma_sync_for_cpu(struct ivtv *itv) | ||
40 | { | ||
41 | pci_dma_sync_single_for_cpu((struct pci_dev *)itv->dev, itv->udma.SG_handle, | ||
42 | sizeof(itv->udma.SGarray), PCI_DMA_TODEVICE); | ||
43 | } | ||
diff --git a/drivers/media/video/ivtv/ivtv-vbi.c b/drivers/media/video/ivtv/ivtv-vbi.c new file mode 100644 index 000000000000..5efa5a867818 --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-vbi.c | |||
@@ -0,0 +1,538 @@ | |||
1 | /* | ||
2 | Vertical Blank Interval support functions | ||
3 | Copyright (C) 2004-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
4 | |||
5 | This program is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published by | ||
7 | the Free Software Foundation; either version 2 of the License, or | ||
8 | (at your option) any later version. | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with this program; if not, write to the Free Software | ||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | #include "ivtv-driver.h" | ||
21 | #include "ivtv-video.h" | ||
22 | #include "ivtv-vbi.h" | ||
23 | #include "ivtv-ioctl.h" | ||
24 | #include "ivtv-queue.h" | ||
25 | |||
26 | static int odd_parity(u8 c) | ||
27 | { | ||
28 | c ^= (c >> 4); | ||
29 | c ^= (c >> 2); | ||
30 | c ^= (c >> 1); | ||
31 | |||
32 | return c & 1; | ||
33 | } | ||
34 | |||
35 | static void passthrough_vbi_data(struct ivtv *itv, int cnt) | ||
36 | { | ||
37 | int wss = 0; | ||
38 | u8 cc[4] = { 0x80, 0x80, 0x80, 0x80 }; | ||
39 | u8 vps[13]; | ||
40 | int found_cc = 0; | ||
41 | int found_wss = 0; | ||
42 | int found_vps = 0; | ||
43 | int cc_pos = itv->vbi.cc_pos; | ||
44 | int i; | ||
45 | |||
46 | for (i = 0; i < cnt; i++) { | ||
47 | struct v4l2_sliced_vbi_data *d = itv->vbi.sliced_dec_data + i; | ||
48 | |||
49 | if (d->id == V4L2_SLICED_CAPTION_525 && d->line == 21) { | ||
50 | found_cc = 1; | ||
51 | if (d->field) { | ||
52 | cc[2] = d->data[0]; | ||
53 | cc[3] = d->data[1]; | ||
54 | } else { | ||
55 | cc[0] = d->data[0]; | ||
56 | cc[1] = d->data[1]; | ||
57 | } | ||
58 | } | ||
59 | else if (d->id == V4L2_SLICED_VPS && d->line == 16 && d->field == 0) { | ||
60 | memcpy(vps, d->data, sizeof(vps)); | ||
61 | found_vps = 1; | ||
62 | } | ||
63 | else if (d->id == V4L2_SLICED_WSS_625 && d->line == 23 && d->field == 0) { | ||
64 | wss = d->data[0] | d->data[1] << 8; | ||
65 | found_wss = 1; | ||
66 | } | ||
67 | } | ||
68 | |||
69 | if (itv->vbi.wss_found != found_wss || itv->vbi.wss != wss) { | ||
70 | itv->vbi.wss = wss; | ||
71 | itv->vbi.wss_found = found_wss; | ||
72 | set_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags); | ||
73 | } | ||
74 | |||
75 | if (found_vps || itv->vbi.vps_found) { | ||
76 | itv->vbi.vps[0] = vps[2]; | ||
77 | itv->vbi.vps[1] = vps[8]; | ||
78 | itv->vbi.vps[2] = vps[9]; | ||
79 | itv->vbi.vps[3] = vps[10]; | ||
80 | itv->vbi.vps[4] = vps[11]; | ||
81 | itv->vbi.vps_found = found_vps; | ||
82 | set_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags); | ||
83 | } | ||
84 | |||
85 | if (found_cc && cc_pos < sizeof(itv->vbi.cc_data_even)) { | ||
86 | itv->vbi.cc_data_odd[cc_pos] = cc[0]; | ||
87 | itv->vbi.cc_data_odd[cc_pos + 1] = cc[1]; | ||
88 | itv->vbi.cc_data_even[cc_pos] = cc[2]; | ||
89 | itv->vbi.cc_data_even[cc_pos + 1] = cc[3]; | ||
90 | itv->vbi.cc_pos = cc_pos + 2; | ||
91 | set_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags); | ||
92 | } | ||
93 | } | ||
94 | |||
95 | static void copy_vbi_data(struct ivtv *itv, int lines, u32 pts_stamp) | ||
96 | { | ||
97 | int line = 0; | ||
98 | int i; | ||
99 | u32 linemask[2] = { 0, 0 }; | ||
100 | unsigned short size; | ||
101 | static const u8 mpeg_hdr_data[] = { | ||
102 | 0x00, 0x00, 0x01, 0xba, 0x44, 0x00, 0x0c, 0x66, | ||
103 | 0x24, 0x01, 0x01, 0xd1, 0xd3, 0xfa, 0xff, 0xff, | ||
104 | 0x00, 0x00, 0x01, 0xbd, 0x00, 0x1a, 0x84, 0x80, | ||
105 | 0x07, 0x21, 0x00, 0x5d, 0x63, 0xa7, 0xff, 0xff | ||
106 | }; | ||
107 | const int sd = sizeof(mpeg_hdr_data); /* start of vbi data */ | ||
108 | int idx = itv->vbi.frame % IVTV_VBI_FRAMES; | ||
109 | u8 *dst = &itv->vbi.sliced_mpeg_data[idx][0]; | ||
110 | |||
111 | for (i = 0; i < lines; i++) { | ||
112 | int f, l; | ||
113 | |||
114 | if (itv->vbi.sliced_data[i].id == 0) | ||
115 | continue; | ||
116 | |||
117 | l = itv->vbi.sliced_data[i].line - 6; | ||
118 | f = itv->vbi.sliced_data[i].field; | ||
119 | if (f) | ||
120 | l += 18; | ||
121 | if (l < 32) | ||
122 | linemask[0] |= (1 << l); | ||
123 | else | ||
124 | linemask[1] |= (1 << (l - 32)); | ||
125 | dst[sd + 12 + line * 43] = service2vbi(itv->vbi.sliced_data[i].id); | ||
126 | memcpy(dst + sd + 12 + line * 43 + 1, itv->vbi.sliced_data[i].data, 42); | ||
127 | line++; | ||
128 | } | ||
129 | memcpy(dst, mpeg_hdr_data, sizeof(mpeg_hdr_data)); | ||
130 | if (line == 36) { | ||
131 | /* All lines are used, so there is no space for the linemask | ||
132 | (the max size of the VBI data is 36 * 43 + 4 bytes). | ||
133 | So in this case we use the magic number 'ITV0'. */ | ||
134 | memcpy(dst + sd, "ITV0", 4); | ||
135 | memcpy(dst + sd + 4, dst + sd + 12, line * 43); | ||
136 | size = 4 + ((43 * line + 3) & ~3); | ||
137 | } else { | ||
138 | memcpy(dst + sd, "itv0", 4); | ||
139 | memcpy(dst + sd + 4, &linemask[0], 8); | ||
140 | size = 12 + ((43 * line + 3) & ~3); | ||
141 | } | ||
142 | dst[4+16] = (size + 10) >> 8; | ||
143 | dst[5+16] = (size + 10) & 0xff; | ||
144 | dst[9+16] = 0x21 | ((pts_stamp >> 29) & 0x6); | ||
145 | dst[10+16] = (pts_stamp >> 22) & 0xff; | ||
146 | dst[11+16] = 1 | ((pts_stamp >> 14) & 0xff); | ||
147 | dst[12+16] = (pts_stamp >> 7) & 0xff; | ||
148 | dst[13+16] = 1 | ((pts_stamp & 0x7f) << 1); | ||
149 | itv->vbi.sliced_mpeg_size[idx] = sd + size; | ||
150 | } | ||
151 | |||
152 | static int ivtv_convert_ivtv_vbi(struct ivtv *itv, u8 *p) | ||
153 | { | ||
154 | u32 linemask[2]; | ||
155 | int i, l, id2; | ||
156 | int line = 0; | ||
157 | |||
158 | if (!memcmp(p, "itv0", 4)) { | ||
159 | memcpy(linemask, p + 4, 8); | ||
160 | p += 12; | ||
161 | } else if (!memcmp(p, "ITV0", 4)) { | ||
162 | linemask[0] = 0xffffffff; | ||
163 | linemask[1] = 0xf; | ||
164 | p += 4; | ||
165 | } else { | ||
166 | /* unknown VBI data stream */ | ||
167 | return 0; | ||
168 | } | ||
169 | for (i = 0; i < 36; i++) { | ||
170 | int err = 0; | ||
171 | |||
172 | if (i < 32 && !(linemask[0] & (1 << i))) | ||
173 | continue; | ||
174 | if (i >= 32 && !(linemask[1] & (1 << (i - 32)))) | ||
175 | continue; | ||
176 | id2 = *p & 0xf; | ||
177 | switch (id2) { | ||
178 | case IVTV_SLICED_TYPE_TELETEXT_B: | ||
179 | id2 = V4L2_SLICED_TELETEXT_B; | ||
180 | break; | ||
181 | case IVTV_SLICED_TYPE_CAPTION_525: | ||
182 | id2 = V4L2_SLICED_CAPTION_525; | ||
183 | err = !odd_parity(p[1]) || !odd_parity(p[2]); | ||
184 | break; | ||
185 | case IVTV_SLICED_TYPE_VPS: | ||
186 | id2 = V4L2_SLICED_VPS; | ||
187 | break; | ||
188 | case IVTV_SLICED_TYPE_WSS_625: | ||
189 | id2 = V4L2_SLICED_WSS_625; | ||
190 | break; | ||
191 | default: | ||
192 | id2 = 0; | ||
193 | break; | ||
194 | } | ||
195 | if (err == 0) { | ||
196 | l = (i < 18) ? i + 6 : i - 18 + 6; | ||
197 | itv->vbi.sliced_dec_data[line].line = l; | ||
198 | itv->vbi.sliced_dec_data[line].field = i >= 18; | ||
199 | itv->vbi.sliced_dec_data[line].id = id2; | ||
200 | memcpy(itv->vbi.sliced_dec_data[line].data, p + 1, 42); | ||
201 | line++; | ||
202 | } | ||
203 | p += 43; | ||
204 | } | ||
205 | while (line < 36) { | ||
206 | itv->vbi.sliced_dec_data[line].id = 0; | ||
207 | itv->vbi.sliced_dec_data[line].line = 0; | ||
208 | itv->vbi.sliced_dec_data[line].field = 0; | ||
209 | line++; | ||
210 | } | ||
211 | return line * sizeof(itv->vbi.sliced_dec_data[0]); | ||
212 | } | ||
213 | |||
214 | ssize_t ivtv_write_vbi(struct ivtv *itv, const char __user *ubuf, size_t count) | ||
215 | { | ||
216 | /* Should be a __user pointer, but sparse doesn't parse this bit correctly. */ | ||
217 | const struct v4l2_sliced_vbi_data *p = (const struct v4l2_sliced_vbi_data *)ubuf; | ||
218 | u8 cc[4] = { 0x80, 0x80, 0x80, 0x80 }; | ||
219 | int found_cc = 0; | ||
220 | int cc_pos = itv->vbi.cc_pos; | ||
221 | |||
222 | if (itv->vbi.service_set_out == 0) | ||
223 | return -EPERM; | ||
224 | |||
225 | while (count >= sizeof(struct v4l2_sliced_vbi_data)) { | ||
226 | switch (p->id) { | ||
227 | case V4L2_SLICED_CAPTION_525: | ||
228 | if (p->id == V4L2_SLICED_CAPTION_525 && | ||
229 | p->line == 21 && | ||
230 | (itv->vbi.service_set_out & | ||
231 | V4L2_SLICED_CAPTION_525) == 0) { | ||
232 | break; | ||
233 | } | ||
234 | found_cc = 1; | ||
235 | if (p->field) { | ||
236 | cc[2] = p->data[0]; | ||
237 | cc[3] = p->data[1]; | ||
238 | } else { | ||
239 | cc[0] = p->data[0]; | ||
240 | cc[1] = p->data[1]; | ||
241 | } | ||
242 | break; | ||
243 | |||
244 | case V4L2_SLICED_VPS: | ||
245 | if (p->line == 16 && p->field == 0 && | ||
246 | (itv->vbi.service_set_out & V4L2_SLICED_VPS)) { | ||
247 | itv->vbi.vps[0] = p->data[2]; | ||
248 | itv->vbi.vps[1] = p->data[8]; | ||
249 | itv->vbi.vps[2] = p->data[9]; | ||
250 | itv->vbi.vps[3] = p->data[10]; | ||
251 | itv->vbi.vps[4] = p->data[11]; | ||
252 | itv->vbi.vps_found = 1; | ||
253 | set_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags); | ||
254 | } | ||
255 | break; | ||
256 | |||
257 | case V4L2_SLICED_WSS_625: | ||
258 | if (p->line == 23 && p->field == 0 && | ||
259 | (itv->vbi.service_set_out & V4L2_SLICED_WSS_625)) { | ||
260 | /* No lock needed for WSS */ | ||
261 | itv->vbi.wss = p->data[0] | (p->data[1] << 8); | ||
262 | itv->vbi.wss_found = 1; | ||
263 | set_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags); | ||
264 | } | ||
265 | break; | ||
266 | |||
267 | default: | ||
268 | break; | ||
269 | } | ||
270 | count -= sizeof(*p); | ||
271 | p++; | ||
272 | } | ||
273 | |||
274 | if (found_cc && cc_pos < sizeof(itv->vbi.cc_data_even)) { | ||
275 | itv->vbi.cc_data_odd[cc_pos] = cc[0]; | ||
276 | itv->vbi.cc_data_odd[cc_pos + 1] = cc[1]; | ||
277 | itv->vbi.cc_data_even[cc_pos] = cc[2]; | ||
278 | itv->vbi.cc_data_even[cc_pos + 1] = cc[3]; | ||
279 | itv->vbi.cc_pos = cc_pos + 2; | ||
280 | set_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags); | ||
281 | } | ||
282 | |||
283 | return (const char __user *)p - ubuf; | ||
284 | } | ||
285 | |||
286 | /* Compress raw VBI format, removes leading SAV codes and surplus space after the | ||
287 | field. | ||
288 | Returns new compressed size. */ | ||
289 | static u32 compress_raw_buf(struct ivtv *itv, u8 *buf, u32 size) | ||
290 | { | ||
291 | u32 line_size = itv->vbi.raw_decoder_line_size; | ||
292 | u32 lines = itv->vbi.count; | ||
293 | u8 sav1 = itv->vbi.raw_decoder_sav_odd_field; | ||
294 | u8 sav2 = itv->vbi.raw_decoder_sav_even_field; | ||
295 | u8 *q = buf; | ||
296 | u8 *p; | ||
297 | int i; | ||
298 | |||
299 | for (i = 0; i < lines; i++) { | ||
300 | p = buf + i * line_size; | ||
301 | |||
302 | /* Look for SAV code */ | ||
303 | if (p[0] != 0xff || p[1] || p[2] || (p[3] != sav1 && p[3] != sav2)) { | ||
304 | break; | ||
305 | } | ||
306 | memcpy(q, p + 4, line_size - 4); | ||
307 | q += line_size - 4; | ||
308 | } | ||
309 | return lines * (line_size - 4); | ||
310 | } | ||
311 | |||
312 | |||
313 | /* Compressed VBI format, all found sliced blocks put next to one another | ||
314 | Returns new compressed size */ | ||
315 | static u32 compress_sliced_buf(struct ivtv *itv, u32 line, u8 *buf, u32 size, u8 sav) | ||
316 | { | ||
317 | u32 line_size = itv->vbi.sliced_decoder_line_size; | ||
318 | struct v4l2_decode_vbi_line vbi; | ||
319 | int i; | ||
320 | |||
321 | /* find the first valid line */ | ||
322 | for (i = 0; i < size; i++, buf++) { | ||
323 | if (buf[0] == 0xff && !buf[1] && !buf[2] && buf[3] == sav) | ||
324 | break; | ||
325 | } | ||
326 | |||
327 | size -= i; | ||
328 | if (size < line_size) { | ||
329 | return line; | ||
330 | } | ||
331 | for (i = 0; i < size / line_size; i++) { | ||
332 | u8 *p = buf + i * line_size; | ||
333 | |||
334 | /* Look for SAV code */ | ||
335 | if (p[0] != 0xff || p[1] || p[2] || p[3] != sav) { | ||
336 | continue; | ||
337 | } | ||
338 | vbi.p = p + 4; | ||
339 | itv->video_dec_func(itv, VIDIOC_INT_DECODE_VBI_LINE, &vbi); | ||
340 | if (vbi.type) { | ||
341 | itv->vbi.sliced_data[line].id = vbi.type; | ||
342 | itv->vbi.sliced_data[line].field = vbi.is_second_field; | ||
343 | itv->vbi.sliced_data[line].line = vbi.line; | ||
344 | memcpy(itv->vbi.sliced_data[line].data, vbi.p, 42); | ||
345 | line++; | ||
346 | } | ||
347 | } | ||
348 | return line; | ||
349 | } | ||
350 | |||
351 | void ivtv_process_vbi_data(struct ivtv *itv, struct ivtv_buffer *buf, | ||
352 | u64 pts_stamp, int streamtype) | ||
353 | { | ||
354 | u8 *p = (u8 *) buf->buf; | ||
355 | u32 size = buf->bytesused; | ||
356 | int y; | ||
357 | |||
358 | /* Raw VBI data */ | ||
359 | if (streamtype == IVTV_ENC_STREAM_TYPE_VBI && itv->vbi.sliced_in->service_set == 0) { | ||
360 | u8 type; | ||
361 | |||
362 | ivtv_buf_swap(buf); | ||
363 | |||
364 | type = p[3]; | ||
365 | |||
366 | size = buf->bytesused = compress_raw_buf(itv, p, size); | ||
367 | |||
368 | /* second field of the frame? */ | ||
369 | if (type == itv->vbi.raw_decoder_sav_even_field) { | ||
370 | /* Dirty hack needed for backwards | ||
371 | compatibility of old VBI software. */ | ||
372 | p += size - 4; | ||
373 | memcpy(p, &itv->vbi.frame, 4); | ||
374 | itv->vbi.frame++; | ||
375 | } | ||
376 | return; | ||
377 | } | ||
378 | |||
379 | /* Sliced VBI data with data insertion */ | ||
380 | if (streamtype == IVTV_ENC_STREAM_TYPE_VBI) { | ||
381 | int lines; | ||
382 | |||
383 | ivtv_buf_swap(buf); | ||
384 | |||
385 | /* first field */ | ||
386 | lines = compress_sliced_buf(itv, 0, p, size / 2, | ||
387 | itv->vbi.sliced_decoder_sav_odd_field); | ||
388 | /* second field */ | ||
389 | /* experimentation shows that the second half does not always begin | ||
390 | at the exact address. So start a bit earlier (hence 32). */ | ||
391 | lines = compress_sliced_buf(itv, lines, p + size / 2 - 32, size / 2 + 32, | ||
392 | itv->vbi.sliced_decoder_sav_even_field); | ||
393 | /* always return at least one empty line */ | ||
394 | if (lines == 0) { | ||
395 | itv->vbi.sliced_data[0].id = 0; | ||
396 | itv->vbi.sliced_data[0].line = 0; | ||
397 | itv->vbi.sliced_data[0].field = 0; | ||
398 | lines = 1; | ||
399 | } | ||
400 | buf->bytesused = size = lines * sizeof(itv->vbi.sliced_data[0]); | ||
401 | memcpy(p, &itv->vbi.sliced_data[0], size); | ||
402 | |||
403 | if (itv->vbi.insert_mpeg) { | ||
404 | copy_vbi_data(itv, lines, pts_stamp); | ||
405 | } | ||
406 | itv->vbi.frame++; | ||
407 | return; | ||
408 | } | ||
409 | |||
410 | /* Sliced VBI re-inserted from an MPEG stream */ | ||
411 | if (streamtype == IVTV_DEC_STREAM_TYPE_VBI) { | ||
412 | /* If the size is not 4-byte aligned, then the starting address | ||
413 | for the swapping is also shifted. After swapping the data the | ||
414 | real start address of the VBI data is exactly 4 bytes after the | ||
415 | original start. It's a bit fiddly but it works like a charm. | ||
416 | Non-4-byte alignment happens when an lseek is done on the input | ||
417 | mpeg file to a non-4-byte aligned position. So on arrival here | ||
418 | the VBI data is also non-4-byte aligned. */ | ||
419 | int offset = size & 3; | ||
420 | int cnt; | ||
421 | |||
422 | if (offset) { | ||
423 | p += 4 - offset; | ||
424 | } | ||
425 | /* Swap Buffer */ | ||
426 | for (y = 0; y < size; y += 4) { | ||
427 | swab32s((u32 *)(p + y)); | ||
428 | } | ||
429 | |||
430 | cnt = ivtv_convert_ivtv_vbi(itv, p + offset); | ||
431 | memcpy(buf->buf, itv->vbi.sliced_dec_data, cnt); | ||
432 | buf->bytesused = cnt; | ||
433 | |||
434 | passthrough_vbi_data(itv, cnt / sizeof(itv->vbi.sliced_dec_data[0])); | ||
435 | return; | ||
436 | } | ||
437 | } | ||
438 | |||
439 | void ivtv_disable_vbi(struct ivtv *itv) | ||
440 | { | ||
441 | clear_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags); | ||
442 | clear_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags); | ||
443 | clear_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags); | ||
444 | ivtv_set_wss(itv, 0, 0); | ||
445 | ivtv_set_cc(itv, 0, 0, 0, 0, 0); | ||
446 | ivtv_set_vps(itv, 0, 0, 0, 0, 0, 0); | ||
447 | itv->vbi.vps_found = itv->vbi.wss_found = 0; | ||
448 | itv->vbi.wss = 0; | ||
449 | itv->vbi.cc_pos = 0; | ||
450 | } | ||
451 | |||
452 | |||
453 | void vbi_work_handler(struct ivtv *itv) | ||
454 | { | ||
455 | struct v4l2_sliced_vbi_data data; | ||
456 | |||
457 | /* Lock */ | ||
458 | if (itv->output_mode == OUT_PASSTHROUGH) { | ||
459 | /* Note: currently only the saa7115 is used in a PVR350, | ||
460 | so these commands are for now saa7115 specific. */ | ||
461 | if (itv->is_50hz) { | ||
462 | data.id = V4L2_SLICED_WSS_625; | ||
463 | data.field = 0; | ||
464 | |||
465 | if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) { | ||
466 | ivtv_set_wss(itv, 1, data.data[0] & 0xf); | ||
467 | itv->vbi.wss_no_update = 0; | ||
468 | } else if (itv->vbi.wss_no_update == 4) { | ||
469 | ivtv_set_wss(itv, 1, 0x8); /* 4x3 full format */ | ||
470 | } else { | ||
471 | itv->vbi.wss_no_update++; | ||
472 | } | ||
473 | } | ||
474 | else { | ||
475 | u8 c1 = 0, c2 = 0, c3 = 0, c4 = 0; | ||
476 | int mode = 0; | ||
477 | |||
478 | data.id = V4L2_SLICED_CAPTION_525; | ||
479 | data.field = 0; | ||
480 | if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) { | ||
481 | mode |= 1; | ||
482 | c1 = data.data[0]; | ||
483 | c2 = data.data[1]; | ||
484 | } | ||
485 | data.field = 1; | ||
486 | if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) { | ||
487 | mode |= 2; | ||
488 | c3 = data.data[0]; | ||
489 | c4 = data.data[1]; | ||
490 | } | ||
491 | if (mode) { | ||
492 | itv->vbi.cc_no_update = 0; | ||
493 | ivtv_set_cc(itv, mode, c1, c2, c3, c4); | ||
494 | } else if (itv->vbi.cc_no_update == 4) { | ||
495 | ivtv_set_cc(itv, 0, 0, 0, 0, 0); | ||
496 | } else { | ||
497 | itv->vbi.cc_no_update++; | ||
498 | } | ||
499 | } | ||
500 | return; | ||
501 | } | ||
502 | |||
503 | if (test_and_clear_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags)) { | ||
504 | /* Lock */ | ||
505 | ivtv_set_wss(itv, itv->vbi.wss_found, itv->vbi.wss & 0xf); | ||
506 | } | ||
507 | |||
508 | if (test_and_clear_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags)) { | ||
509 | if (itv->vbi.cc_pos == 0) { | ||
510 | ivtv_set_cc(itv, 3, 0x80, 0x80, 0x80, 0x80); | ||
511 | } | ||
512 | while (itv->vbi.cc_pos) { | ||
513 | u8 cc_odd0 = itv->vbi.cc_data_odd[0]; | ||
514 | u8 cc_odd1 = itv->vbi.cc_data_odd[1]; | ||
515 | u8 cc_even0 = itv->vbi.cc_data_even[0]; | ||
516 | u8 cc_even1 = itv->vbi.cc_data_even[1]; | ||
517 | |||
518 | memcpy(itv->vbi.cc_data_odd, itv->vbi.cc_data_odd + 2, sizeof(itv->vbi.cc_data_odd) - 2); | ||
519 | memcpy(itv->vbi.cc_data_even, itv->vbi.cc_data_even + 2, sizeof(itv->vbi.cc_data_even) - 2); | ||
520 | itv->vbi.cc_pos -= 2; | ||
521 | if (itv->vbi.cc_pos && cc_odd0 == 0x80 && cc_odd1 == 0x80) | ||
522 | continue; | ||
523 | |||
524 | /* Send to Saa7127 */ | ||
525 | ivtv_set_cc(itv, 3, cc_odd0, cc_odd1, cc_even0, cc_even1); | ||
526 | if (itv->vbi.cc_pos == 0) | ||
527 | set_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags); | ||
528 | break; | ||
529 | } | ||
530 | } | ||
531 | |||
532 | if (test_and_clear_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags)) { | ||
533 | /* Lock */ | ||
534 | ivtv_set_vps(itv, itv->vbi.vps_found, | ||
535 | itv->vbi.vps[0], itv->vbi.vps[1], | ||
536 | itv->vbi.vps[2], itv->vbi.vps[3], itv->vbi.vps[4]); | ||
537 | } | ||
538 | } | ||
diff --git a/drivers/media/video/ivtv/ivtv-vbi.h b/drivers/media/video/ivtv/ivtv-vbi.h new file mode 100644 index 000000000000..cdaea697b3ec --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-vbi.h | |||
@@ -0,0 +1,26 @@ | |||
1 | /* | ||
2 | Vertical Blank Interval support functions | ||
3 | Copyright (C) 2004-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
4 | |||
5 | This program is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published by | ||
7 | the Free Software Foundation; either version 2 of the License, or | ||
8 | (at your option) any later version. | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with this program; if not, write to the Free Software | ||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | ssize_t ivtv_write_vbi(struct ivtv *itv, const char __user *ubuf, size_t count); | ||
21 | void ivtv_process_vbi_data(struct ivtv *itv, struct ivtv_buffer *buf, | ||
22 | u64 pts_stamp, int streamtype); | ||
23 | int ivtv_used_line(struct ivtv *itv, int line, int field); | ||
24 | void ivtv_disable_vbi(struct ivtv *itv); | ||
25 | void ivtv_set_vbi(unsigned long arg); | ||
26 | void vbi_work_handler(struct ivtv *itv); | ||
diff --git a/drivers/media/video/ivtv/ivtv-version.h b/drivers/media/video/ivtv/ivtv-version.h new file mode 100644 index 000000000000..85530a3cd369 --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-version.h | |||
@@ -0,0 +1,26 @@ | |||
1 | /* | ||
2 | ivtv driver version information | ||
3 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
4 | |||
5 | This program is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published by | ||
7 | the Free Software Foundation; either version 2 of the License, or | ||
8 | (at your option) any later version. | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with this program; if not, write to the Free Software | ||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | #define IVTV_DRIVER_NAME "ivtv" | ||
21 | #define IVTV_DRIVER_VERSION_MAJOR 1 | ||
22 | #define IVTV_DRIVER_VERSION_MINOR 0 | ||
23 | #define IVTV_DRIVER_VERSION_PATCHLEVEL 0 | ||
24 | |||
25 | #define IVTV_VERSION __stringify(IVTV_DRIVER_VERSION_MAJOR) "." __stringify(IVTV_DRIVER_VERSION_MINOR) "." __stringify(IVTV_DRIVER_VERSION_PATCHLEVEL) | ||
26 | #define IVTV_DRIVER_VERSION KERNEL_VERSION(IVTV_DRIVER_VERSION_MAJOR,IVTV_DRIVER_VERSION_MINOR,IVTV_DRIVER_VERSION_PATCHLEVEL) | ||
diff --git a/drivers/media/video/ivtv/ivtv-video.c b/drivers/media/video/ivtv/ivtv-video.c new file mode 100644 index 000000000000..5858b197d510 --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-video.c | |||
@@ -0,0 +1,142 @@ | |||
1 | /* | ||
2 | saa7127 interface functions | ||
3 | Copyright (C) 2004-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
4 | |||
5 | This program is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published by | ||
7 | the Free Software Foundation; either version 2 of the License, or | ||
8 | (at your option) any later version. | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with this program; if not, write to the Free Software | ||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | #include "ivtv-driver.h" | ||
21 | #include "ivtv-video.h" | ||
22 | #include "ivtv-i2c.h" | ||
23 | #include "ivtv-gpio.h" | ||
24 | #include "ivtv-cards.h" | ||
25 | #include <media/upd64031a.h> | ||
26 | #include <media/upd64083.h> | ||
27 | |||
28 | void ivtv_set_vps(struct ivtv *itv, int enabled, u8 vps1, u8 vps2, u8 vps3, | ||
29 | u8 vps4, u8 vps5) | ||
30 | { | ||
31 | struct v4l2_sliced_vbi_data data; | ||
32 | |||
33 | if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) | ||
34 | return; | ||
35 | data.id = V4L2_SLICED_VPS; | ||
36 | data.field = 0; | ||
37 | data.line = enabled ? 16 : 0; | ||
38 | data.data[4] = vps1; | ||
39 | data.data[10] = vps2; | ||
40 | data.data[11] = vps3; | ||
41 | data.data[12] = vps4; | ||
42 | data.data[13] = vps5; | ||
43 | ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data); | ||
44 | } | ||
45 | |||
46 | void ivtv_set_cc(struct ivtv *itv, int mode, u8 cc1, u8 cc2, u8 cc3, u8 cc4) | ||
47 | { | ||
48 | struct v4l2_sliced_vbi_data data; | ||
49 | |||
50 | if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) | ||
51 | return; | ||
52 | data.id = V4L2_SLICED_CAPTION_525; | ||
53 | data.field = 0; | ||
54 | data.line = (mode & 1) ? 21 : 0; | ||
55 | data.data[0] = cc1; | ||
56 | data.data[1] = cc2; | ||
57 | ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data); | ||
58 | data.field = 1; | ||
59 | data.line = (mode & 2) ? 21 : 0; | ||
60 | data.data[0] = cc3; | ||
61 | data.data[1] = cc4; | ||
62 | ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data); | ||
63 | } | ||
64 | |||
65 | void ivtv_set_wss(struct ivtv *itv, int enabled, int mode) | ||
66 | { | ||
67 | struct v4l2_sliced_vbi_data data; | ||
68 | |||
69 | if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) | ||
70 | return; | ||
71 | /* When using a 50 Hz system, always turn on the | ||
72 | wide screen signal with 4x3 ratio as the default. | ||
73 | Turning this signal on and off can confuse certain | ||
74 | TVs. As far as I can tell there is no reason not to | ||
75 | transmit this signal. */ | ||
76 | if ((itv->std & V4L2_STD_625_50) && !enabled) { | ||
77 | enabled = 1; | ||
78 | mode = 0x08; /* 4x3 full format */ | ||
79 | } | ||
80 | data.id = V4L2_SLICED_WSS_625; | ||
81 | data.field = 0; | ||
82 | data.line = enabled ? 23 : 0; | ||
83 | data.data[0] = mode & 0xff; | ||
84 | data.data[1] = (mode >> 8) & 0xff; | ||
85 | ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data); | ||
86 | } | ||
87 | |||
88 | void ivtv_video_set_io(struct ivtv *itv) | ||
89 | { | ||
90 | struct v4l2_routing route; | ||
91 | int inp = itv->active_input; | ||
92 | u32 type; | ||
93 | |||
94 | route.input = itv->card->video_inputs[inp].video_input; | ||
95 | route.output = 0; | ||
96 | itv->video_dec_func(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route); | ||
97 | |||
98 | type = itv->card->video_inputs[inp].video_type; | ||
99 | |||
100 | if (type == IVTV_CARD_INPUT_VID_TUNER) { | ||
101 | route.input = 0; /* Tuner */ | ||
102 | } else if (type < IVTV_CARD_INPUT_COMPOSITE1) { | ||
103 | route.input = 2; /* S-Video */ | ||
104 | } else { | ||
105 | route.input = 1; /* Composite */ | ||
106 | } | ||
107 | |||
108 | if (itv->card->hw_video & IVTV_HW_GPIO) | ||
109 | ivtv_gpio(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route); | ||
110 | |||
111 | if (itv->card->hw_video & IVTV_HW_UPD64031A) { | ||
112 | if (type == IVTV_CARD_INPUT_VID_TUNER || | ||
113 | type >= IVTV_CARD_INPUT_COMPOSITE1) { | ||
114 | /* Composite: GR on, connect to 3DYCS */ | ||
115 | route.input = UPD64031A_GR_ON | UPD64031A_3DYCS_COMPOSITE; | ||
116 | } else { | ||
117 | /* S-Video: GR bypassed, turn it off */ | ||
118 | route.input = UPD64031A_GR_OFF | UPD64031A_3DYCS_DISABLE; | ||
119 | } | ||
120 | route.input |= itv->card->gr_config; | ||
121 | |||
122 | ivtv_upd64031a(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route); | ||
123 | } | ||
124 | |||
125 | if (itv->card->hw_video & IVTV_HW_UPD6408X) { | ||
126 | route.input = UPD64083_YCS_MODE; | ||
127 | if (type > IVTV_CARD_INPUT_VID_TUNER && | ||
128 | type < IVTV_CARD_INPUT_COMPOSITE1) { | ||
129 | /* S-Video uses YCNR mode and internal Y-ADC, the upd64031a | ||
130 | is not used. */ | ||
131 | route.input |= UPD64083_YCNR_MODE; | ||
132 | } | ||
133 | else if (itv->card->hw_video & IVTV_HW_UPD64031A) { | ||
134 | /* Use upd64031a output for tuner and composite(CX23416GYC only) inputs */ | ||
135 | if ((type == IVTV_CARD_INPUT_VID_TUNER)|| | ||
136 | (itv->card->type == IVTV_CARD_CX23416GYC)) { | ||
137 | route.input |= UPD64083_EXT_Y_ADC; | ||
138 | } | ||
139 | } | ||
140 | ivtv_upd64083(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route); | ||
141 | } | ||
142 | } | ||
diff --git a/drivers/media/video/ivtv/ivtv-video.h b/drivers/media/video/ivtv/ivtv-video.h new file mode 100644 index 000000000000..c8ade5d3c413 --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-video.h | |||
@@ -0,0 +1,24 @@ | |||
1 | /* | ||
2 | saa7127 interface functions | ||
3 | Copyright (C) 2004-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
4 | |||
5 | This program is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published by | ||
7 | the Free Software Foundation; either version 2 of the License, or | ||
8 | (at your option) any later version. | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with this program; if not, write to the Free Software | ||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | void ivtv_set_wss(struct ivtv *itv, int enabled, int mode); | ||
21 | void ivtv_set_cc(struct ivtv *itv, int mode, u8 cc1, u8 cc2, u8 cc3, u8 cc4); | ||
22 | void ivtv_set_vps(struct ivtv *itv, int enabled, u8 vps1, u8 vps2, u8 vps3, | ||
23 | u8 vps4, u8 vps5); | ||
24 | void ivtv_video_set_io(struct ivtv *itv); | ||
diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c new file mode 100644 index 000000000000..bcea09542e5a --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-yuv.c | |||
@@ -0,0 +1,1129 @@ | |||
1 | /* | ||
2 | yuv support | ||
3 | |||
4 | Copyright (C) 2007 Ian Armstrong <ian@iarmst.demon.co.uk> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | #include "ivtv-driver.h" | ||
22 | #include "ivtv-queue.h" | ||
23 | #include "ivtv-udma.h" | ||
24 | #include "ivtv-irq.h" | ||
25 | #include "ivtv-yuv.h" | ||
26 | |||
27 | static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma, | ||
28 | struct ivtv_dma_frame *args) | ||
29 | { | ||
30 | struct ivtv_dma_page_info y_dma; | ||
31 | struct ivtv_dma_page_info uv_dma; | ||
32 | |||
33 | int i; | ||
34 | int y_pages, uv_pages; | ||
35 | |||
36 | unsigned long y_buffer_offset, uv_buffer_offset; | ||
37 | int y_decode_height, uv_decode_height, y_size; | ||
38 | int frame = atomic_read(&itv->yuv_info.next_fill_frame); | ||
39 | |||
40 | y_buffer_offset = IVTV_DEC_MEM_START + yuv_offset[frame]; | ||
41 | uv_buffer_offset = y_buffer_offset + IVTV_YUV_BUFFER_UV_OFFSET; | ||
42 | |||
43 | y_decode_height = uv_decode_height = args->src.height + args->src.top; | ||
44 | |||
45 | if (y_decode_height < 512-16) | ||
46 | y_buffer_offset += 720 * 16; | ||
47 | |||
48 | if (y_decode_height & 15) | ||
49 | y_decode_height = (y_decode_height + 16) & ~15; | ||
50 | |||
51 | if (uv_decode_height & 31) | ||
52 | uv_decode_height = (uv_decode_height + 32) & ~31; | ||
53 | |||
54 | y_size = 720 * y_decode_height; | ||
55 | |||
56 | /* Still in USE */ | ||
57 | if (dma->SG_length || dma->page_count) { | ||
58 | IVTV_DEBUG_WARN("prep_user_dma: SG_length %d page_count %d still full?\n", | ||
59 | dma->SG_length, dma->page_count); | ||
60 | return -EBUSY; | ||
61 | } | ||
62 | |||
63 | ivtv_udma_get_page_info (&y_dma, (unsigned long)args->y_source, 720 * y_decode_height); | ||
64 | ivtv_udma_get_page_info (&uv_dma, (unsigned long)args->uv_source, 360 * uv_decode_height); | ||
65 | |||
66 | /* Get user pages for DMA Xfer */ | ||
67 | down_read(¤t->mm->mmap_sem); | ||
68 | y_pages = get_user_pages(current, current->mm, y_dma.uaddr, y_dma.page_count, 0, 1, &dma->map[0], NULL); | ||
69 | uv_pages = get_user_pages(current, current->mm, uv_dma.uaddr, uv_dma.page_count, 0, 1, &dma->map[y_pages], NULL); | ||
70 | up_read(¤t->mm->mmap_sem); | ||
71 | |||
72 | dma->page_count = y_dma.page_count + uv_dma.page_count; | ||
73 | |||
74 | if (y_pages + uv_pages != dma->page_count) { | ||
75 | IVTV_DEBUG_WARN("failed to map user pages, returned %d instead of %d\n", | ||
76 | y_pages + uv_pages, dma->page_count); | ||
77 | |||
78 | for (i = 0; i < dma->page_count; i++) { | ||
79 | put_page(dma->map[i]); | ||
80 | } | ||
81 | dma->page_count = 0; | ||
82 | return -EINVAL; | ||
83 | } | ||
84 | |||
85 | /* Fill & map SG List */ | ||
86 | ivtv_udma_fill_sg_list (dma, &uv_dma, ivtv_udma_fill_sg_list (dma, &y_dma, 0)); | ||
87 | dma->SG_length = pci_map_sg(itv->dev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE); | ||
88 | |||
89 | /* Fill SG Array with new values */ | ||
90 | ivtv_udma_fill_sg_array (dma, y_buffer_offset, uv_buffer_offset, y_size); | ||
91 | |||
92 | /* If we've offset the y plane, ensure top area is blanked */ | ||
93 | if (args->src.height + args->src.top < 512-16) { | ||
94 | if (itv->yuv_info.blanking_dmaptr) { | ||
95 | dma->SGarray[dma->SG_length].size = cpu_to_le32(720*16); | ||
96 | dma->SGarray[dma->SG_length].src = cpu_to_le32(itv->yuv_info.blanking_dmaptr); | ||
97 | dma->SGarray[dma->SG_length].dst = cpu_to_le32(IVTV_DEC_MEM_START + yuv_offset[frame]); | ||
98 | dma->SG_length++; | ||
99 | } | ||
100 | } | ||
101 | |||
102 | /* Tag SG Array with Interrupt Bit */ | ||
103 | dma->SGarray[dma->SG_length - 1].size |= cpu_to_le32(0x80000000); | ||
104 | |||
105 | ivtv_udma_sync_for_device(itv); | ||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | /* We rely on a table held in the firmware - Quick check. */ | ||
110 | int ivtv_yuv_filter_check(struct ivtv *itv) | ||
111 | { | ||
112 | int i, offset_y, offset_uv; | ||
113 | |||
114 | for (i=0, offset_y = 16, offset_uv = 4; i<16; i++, offset_y += 24, offset_uv += 12) { | ||
115 | if ((read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + offset_y) != i << 16) || | ||
116 | (read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + offset_uv) != i << 16)) { | ||
117 | IVTV_WARN ("YUV filter table not found in firmware.\n"); | ||
118 | return -1; | ||
119 | } | ||
120 | } | ||
121 | return 0; | ||
122 | } | ||
123 | |||
124 | static void ivtv_yuv_filter(struct ivtv *itv, int h_filter, int v_filter_1, int v_filter_2) | ||
125 | { | ||
126 | int filter_index, filter_line; | ||
127 | |||
128 | /* If any filter is -1, then don't update it */ | ||
129 | if (h_filter > -1) { | ||
130 | if (h_filter > 4) h_filter = 4; | ||
131 | filter_index = h_filter * 384; | ||
132 | filter_line = 0; | ||
133 | while (filter_line < 16) { | ||
134 | write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02804); | ||
135 | write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x0281c); | ||
136 | filter_index += 4; | ||
137 | write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02808); | ||
138 | write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02820); | ||
139 | filter_index += 4; | ||
140 | write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x0280c); | ||
141 | write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02824); | ||
142 | filter_index += 4; | ||
143 | write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02810); | ||
144 | write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02828); | ||
145 | filter_index += 4; | ||
146 | write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02814); | ||
147 | write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x0282c); | ||
148 | filter_index += 8; | ||
149 | write_reg(0, 0x02818); | ||
150 | write_reg(0, 0x02830); | ||
151 | filter_line ++; | ||
152 | } | ||
153 | IVTV_DEBUG_YUV("h_filter -> %d\n",h_filter); | ||
154 | } | ||
155 | |||
156 | if (v_filter_1 > -1) { | ||
157 | if (v_filter_1 > 4) v_filter_1 = 4; | ||
158 | filter_index = v_filter_1 * 192; | ||
159 | filter_line = 0; | ||
160 | while (filter_line < 16) { | ||
161 | write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x02900); | ||
162 | filter_index += 4; | ||
163 | write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x02904); | ||
164 | filter_index += 8; | ||
165 | write_reg(0, 0x02908); | ||
166 | filter_line ++; | ||
167 | } | ||
168 | IVTV_DEBUG_YUV("v_filter_1 -> %d\n",v_filter_1); | ||
169 | } | ||
170 | |||
171 | if (v_filter_2 > -1) { | ||
172 | if (v_filter_2 > 4) v_filter_2 = 4; | ||
173 | filter_index = v_filter_2 * 192; | ||
174 | filter_line = 0; | ||
175 | while (filter_line < 16) { | ||
176 | write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x0290c); | ||
177 | filter_index += 4; | ||
178 | write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x02910); | ||
179 | filter_index += 8; | ||
180 | write_reg(0, 0x02914); | ||
181 | filter_line ++; | ||
182 | } | ||
183 | IVTV_DEBUG_YUV("v_filter_2 -> %d\n",v_filter_2); | ||
184 | } | ||
185 | } | ||
186 | |||
187 | static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *window) | ||
188 | { | ||
189 | u32 reg_2834, reg_2838, reg_283c; | ||
190 | u32 reg_2844, reg_2854, reg_285c; | ||
191 | u32 reg_2864, reg_2874, reg_2890; | ||
192 | u32 reg_2870, reg_2870_base, reg_2870_offset; | ||
193 | int x_cutoff; | ||
194 | int h_filter; | ||
195 | u32 master_width; | ||
196 | |||
197 | IVTV_DEBUG_WARN( "Need to adjust to width %d src_w %d dst_w %d src_x %d dst_x %d\n", | ||
198 | window->tru_w, window->src_w, window->dst_w,window->src_x, window->dst_x); | ||
199 | |||
200 | /* How wide is the src image */ | ||
201 | x_cutoff = window->src_w + window->src_x; | ||
202 | |||
203 | /* Set the display width */ | ||
204 | reg_2834 = window->dst_w; | ||
205 | reg_2838 = reg_2834; | ||
206 | |||
207 | /* Set the display position */ | ||
208 | reg_2890 = window->dst_x; | ||
209 | |||
210 | /* Index into the image horizontally */ | ||
211 | reg_2870 = 0; | ||
212 | |||
213 | /* 2870 is normally fudged to align video coords with osd coords. | ||
214 | If running full screen, it causes an unwanted left shift | ||
215 | Remove the fudge if we almost fill the screen. | ||
216 | Gradually adjust the offset to avoid the video 'snapping' | ||
217 | left/right if it gets dragged through this region. | ||
218 | Only do this if osd is full width. */ | ||
219 | if (window->vis_w == 720) { | ||
220 | if ((window->tru_x - window->pan_x > -1) && (window->tru_x - window->pan_x <= 40) && (window->dst_w >= 680)){ | ||
221 | reg_2870 = 10 - (window->tru_x - window->pan_x) / 4; | ||
222 | } | ||
223 | else if ((window->tru_x - window->pan_x < 0) && (window->tru_x - window->pan_x >= -20) && (window->dst_w >= 660)) { | ||
224 | reg_2870 = (10 + (window->tru_x - window->pan_x) / 2); | ||
225 | } | ||
226 | |||
227 | if (window->dst_w >= window->src_w) | ||
228 | reg_2870 = reg_2870 << 16 | reg_2870; | ||
229 | else | ||
230 | reg_2870 = ((reg_2870 & ~1) << 15) | (reg_2870 & ~1); | ||
231 | } | ||
232 | |||
233 | if (window->dst_w < window->src_w) | ||
234 | reg_2870 = 0x000d000e - reg_2870; | ||
235 | else | ||
236 | reg_2870 = 0x0012000e - reg_2870; | ||
237 | |||
238 | /* We're also using 2870 to shift the image left (src_x & negative dst_x) */ | ||
239 | reg_2870_offset = (window->src_x*((window->dst_w << 21)/window->src_w))>>19; | ||
240 | |||
241 | if (window->dst_w >= window->src_w) { | ||
242 | x_cutoff &= ~1; | ||
243 | master_width = (window->src_w * 0x00200000) / (window->dst_w); | ||
244 | if (master_width * window->dst_w != window->src_w * 0x00200000) master_width ++; | ||
245 | reg_2834 = (reg_2834 << 16) | x_cutoff; | ||
246 | reg_2838 = (reg_2838 << 16) | x_cutoff; | ||
247 | reg_283c = master_width >> 2; | ||
248 | reg_2844 = master_width >> 2; | ||
249 | reg_2854 = master_width; | ||
250 | reg_285c = master_width >> 1; | ||
251 | reg_2864 = master_width >> 1; | ||
252 | |||
253 | /* We also need to factor in the scaling | ||
254 | (src_w - dst_w) / (src_w / 4) */ | ||
255 | if (window->dst_w > window->src_w) | ||
256 | reg_2870_base = ((window->dst_w - window->src_w)<<16) / (window->src_w <<14); | ||
257 | else | ||
258 | reg_2870_base = 0; | ||
259 | |||
260 | reg_2870 += (((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 2) + (reg_2870_base << 17 | reg_2870_base); | ||
261 | reg_2874 = 0; | ||
262 | } | ||
263 | else if (window->dst_w < window->src_w / 2) { | ||
264 | master_width = (window->src_w * 0x00080000) / window->dst_w; | ||
265 | if (master_width * window->dst_w != window->src_w * 0x00080000) master_width ++; | ||
266 | reg_2834 = (reg_2834 << 16) | x_cutoff; | ||
267 | reg_2838 = (reg_2838 << 16) | x_cutoff; | ||
268 | reg_283c = master_width >> 2; | ||
269 | reg_2844 = master_width >> 1; | ||
270 | reg_2854 = master_width; | ||
271 | reg_285c = master_width >> 1; | ||
272 | reg_2864 = master_width >> 1; | ||
273 | reg_2870 += (((reg_2870_offset << 15) & 0xFFFF0000) | reg_2870_offset); | ||
274 | reg_2870 += (5 - (((window->src_w + window->src_w / 2) - 1) / window->dst_w)) << 16; | ||
275 | reg_2874 = 0x00000012; | ||
276 | } | ||
277 | else { | ||
278 | master_width = (window->src_w * 0x00100000) / window->dst_w; | ||
279 | if (master_width * window->dst_w != window->src_w * 0x00100000) master_width ++; | ||
280 | reg_2834 = (reg_2834 << 16) | x_cutoff; | ||
281 | reg_2838 = (reg_2838 << 16) | x_cutoff; | ||
282 | reg_283c = master_width >> 2; | ||
283 | reg_2844 = master_width >> 1; | ||
284 | reg_2854 = master_width; | ||
285 | reg_285c = master_width >> 1; | ||
286 | reg_2864 = master_width >> 1; | ||
287 | reg_2870 += (((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 1); | ||
288 | reg_2870 += (5 - (((window->src_w * 3) - 1) / window->dst_w)) << 16; | ||
289 | reg_2874 = 0x00000001; | ||
290 | } | ||
291 | |||
292 | /* Select the horizontal filter */ | ||
293 | if (window->src_w == window->dst_w) { | ||
294 | /* An exact size match uses filter 0 */ | ||
295 | h_filter = 0; | ||
296 | } | ||
297 | else { | ||
298 | /* Figure out which filter to use */ | ||
299 | h_filter = ((window->src_w << 16) / window->dst_w) >> 15; | ||
300 | h_filter = (h_filter >> 1) + (h_filter & 1); | ||
301 | /* Only an exact size match can use filter 0 */ | ||
302 | if (h_filter == 0) h_filter = 1; | ||
303 | } | ||
304 | |||
305 | write_reg(reg_2834, 0x02834); | ||
306 | write_reg(reg_2838, 0x02838); | ||
307 | IVTV_DEBUG_YUV("Update reg 0x2834 %08x->%08x 0x2838 %08x->%08x\n",itv->yuv_info.reg_2834, reg_2834, itv->yuv_info.reg_2838, reg_2838); | ||
308 | |||
309 | write_reg(reg_283c, 0x0283c); | ||
310 | write_reg(reg_2844, 0x02844); | ||
311 | |||
312 | IVTV_DEBUG_YUV("Update reg 0x283c %08x->%08x 0x2844 %08x->%08x\n",itv->yuv_info.reg_283c, reg_283c, itv->yuv_info.reg_2844, reg_2844); | ||
313 | |||
314 | write_reg(0x00080514, 0x02840); | ||
315 | write_reg(0x00100514, 0x02848); | ||
316 | IVTV_DEBUG_YUV("Update reg 0x2840 %08x->%08x 0x2848 %08x->%08x\n",itv->yuv_info.reg_2840, 0x00080514, itv->yuv_info.reg_2848, 0x00100514); | ||
317 | |||
318 | write_reg(reg_2854, 0x02854); | ||
319 | IVTV_DEBUG_YUV("Update reg 0x2854 %08x->%08x \n",itv->yuv_info.reg_2854, reg_2854); | ||
320 | |||
321 | write_reg(reg_285c, 0x0285c); | ||
322 | write_reg(reg_2864, 0x02864); | ||
323 | IVTV_DEBUG_YUV("Update reg 0x285c %08x->%08x 0x2864 %08x->%08x\n",itv->yuv_info.reg_285c, reg_285c, itv->yuv_info.reg_2864, reg_2864); | ||
324 | |||
325 | write_reg(reg_2874, 0x02874); | ||
326 | IVTV_DEBUG_YUV("Update reg 0x2874 %08x->%08x\n",itv->yuv_info.reg_2874, reg_2874); | ||
327 | |||
328 | write_reg(reg_2870, 0x02870); | ||
329 | IVTV_DEBUG_YUV("Update reg 0x2870 %08x->%08x\n",itv->yuv_info.reg_2870, reg_2870); | ||
330 | |||
331 | write_reg( reg_2890,0x02890); | ||
332 | IVTV_DEBUG_YUV("Update reg 0x2890 %08x->%08x\n",itv->yuv_info.reg_2890, reg_2890); | ||
333 | |||
334 | /* Only update the filter if we really need to */ | ||
335 | if (h_filter != itv->yuv_info.h_filter) { | ||
336 | ivtv_yuv_filter (itv,h_filter,-1,-1); | ||
337 | itv->yuv_info.h_filter = h_filter; | ||
338 | } | ||
339 | } | ||
340 | |||
341 | static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *window) | ||
342 | { | ||
343 | u32 master_height; | ||
344 | u32 reg_2918, reg_291c, reg_2920, reg_2928; | ||
345 | u32 reg_2930, reg_2934, reg_293c; | ||
346 | u32 reg_2940, reg_2944, reg_294c; | ||
347 | u32 reg_2950, reg_2954, reg_2958, reg_295c; | ||
348 | u32 reg_2960, reg_2964, reg_2968, reg_296c; | ||
349 | u32 reg_289c; | ||
350 | u32 src_y_major_y, src_y_minor_y; | ||
351 | u32 src_y_major_uv, src_y_minor_uv; | ||
352 | u32 reg_2964_base, reg_2968_base; | ||
353 | int v_filter_1, v_filter_2; | ||
354 | |||
355 | IVTV_DEBUG_WARN("Need to adjust to height %d src_h %d dst_h %d src_y %d dst_y %d\n", | ||
356 | window->tru_h, window->src_h, window->dst_h,window->src_y, window->dst_y); | ||
357 | |||
358 | /* What scaling mode is being used... */ | ||
359 | if (window->interlaced_y) { | ||
360 | IVTV_DEBUG_YUV("Scaling mode Y: Interlaced\n"); | ||
361 | } | ||
362 | else { | ||
363 | IVTV_DEBUG_YUV("Scaling mode Y: Progressive\n"); | ||
364 | } | ||
365 | |||
366 | if (window->interlaced_uv) { | ||
367 | IVTV_DEBUG_YUV("Scaling mode UV: Interlaced\n"); | ||
368 | } | ||
369 | else { | ||
370 | IVTV_DEBUG_YUV("Scaling mode UV: Progressive\n"); | ||
371 | } | ||
372 | |||
373 | /* What is the source video being treated as... */ | ||
374 | if (itv->yuv_info.frame_interlaced) { | ||
375 | IVTV_DEBUG_WARN("Source video: Interlaced\n"); | ||
376 | } | ||
377 | else { | ||
378 | IVTV_DEBUG_WARN("Source video: Non-interlaced\n"); | ||
379 | } | ||
380 | |||
381 | /* We offset into the image using two different index methods, so split | ||
382 | the y source coord into two parts. */ | ||
383 | if (window->src_y < 8) { | ||
384 | src_y_minor_uv = window->src_y; | ||
385 | src_y_major_uv = 0; | ||
386 | } | ||
387 | else { | ||
388 | src_y_minor_uv = 8; | ||
389 | src_y_major_uv = window->src_y - 8; | ||
390 | } | ||
391 | |||
392 | src_y_minor_y = src_y_minor_uv; | ||
393 | src_y_major_y = src_y_major_uv; | ||
394 | |||
395 | if (window->offset_y) src_y_minor_y += 16; | ||
396 | |||
397 | if (window->interlaced_y) | ||
398 | reg_2918 = (window->dst_h << 16) | (window->src_h + src_y_minor_y); | ||
399 | else | ||
400 | reg_2918 = (window->dst_h << 16) | ((window->src_h + src_y_minor_y) << 1); | ||
401 | |||
402 | if (window->interlaced_uv) | ||
403 | reg_291c = (window->dst_h << 16) | ((window->src_h + src_y_minor_uv) >> 1); | ||
404 | else | ||
405 | reg_291c = (window->dst_h << 16) | (window->src_h + src_y_minor_uv); | ||
406 | |||
407 | reg_2964_base = (src_y_minor_y * ((window->dst_h << 16)/window->src_h)) >> 14; | ||
408 | reg_2968_base = (src_y_minor_uv * ((window->dst_h << 16)/window->src_h)) >> 14; | ||
409 | |||
410 | if (window->dst_h / 2 >= window->src_h && !window->interlaced_y) { | ||
411 | master_height = (window->src_h * 0x00400000) / window->dst_h; | ||
412 | if ((window->src_h * 0x00400000) - (master_height * window->dst_h) >= window->dst_h / 2) master_height ++; | ||
413 | reg_2920 = master_height >> 2; | ||
414 | reg_2928 = master_height >> 3; | ||
415 | reg_2930 = master_height; | ||
416 | reg_2940 = master_height >> 1; | ||
417 | reg_2964_base >>= 3; | ||
418 | reg_2968_base >>= 3; | ||
419 | reg_296c = 0x00000000; | ||
420 | } | ||
421 | else if (window->dst_h >= window->src_h) { | ||
422 | master_height = (window->src_h * 0x00400000) / window->dst_h; | ||
423 | master_height = (master_height >> 1) + (master_height & 1); | ||
424 | reg_2920 = master_height >> 2; | ||
425 | reg_2928 = master_height >> 2; | ||
426 | reg_2930 = master_height; | ||
427 | reg_2940 = master_height >> 1; | ||
428 | reg_296c = 0x00000000; | ||
429 | if (window->interlaced_y) { | ||
430 | reg_2964_base >>= 3; | ||
431 | } | ||
432 | else { | ||
433 | reg_296c ++; | ||
434 | reg_2964_base >>= 2; | ||
435 | } | ||
436 | if (window->interlaced_uv) reg_2928 >>= 1; | ||
437 | reg_2968_base >>= 3; | ||
438 | } | ||
439 | else if (window->dst_h >= window->src_h / 2) { | ||
440 | master_height = (window->src_h * 0x00200000) / window->dst_h; | ||
441 | master_height = (master_height >> 1) + (master_height & 1); | ||
442 | reg_2920 = master_height >> 2; | ||
443 | reg_2928 = master_height >> 2; | ||
444 | reg_2930 = master_height; | ||
445 | reg_2940 = master_height; | ||
446 | reg_296c = 0x00000101; | ||
447 | if (window->interlaced_y) { | ||
448 | reg_2964_base >>= 2; | ||
449 | } | ||
450 | else { | ||
451 | reg_296c ++; | ||
452 | reg_2964_base >>= 1; | ||
453 | } | ||
454 | if (window->interlaced_uv) reg_2928 >>= 1; | ||
455 | reg_2968_base >>= 2; | ||
456 | } | ||
457 | else { | ||
458 | master_height = (window->src_h * 0x00100000) / window->dst_h; | ||
459 | master_height = (master_height >> 1) + (master_height & 1); | ||
460 | reg_2920 = master_height >> 2; | ||
461 | reg_2928 = master_height >> 2; | ||
462 | reg_2930 = master_height; | ||
463 | reg_2940 = master_height; | ||
464 | reg_2964_base >>= 1; | ||
465 | reg_2968_base >>= 2; | ||
466 | reg_296c = 0x00000102; | ||
467 | } | ||
468 | |||
469 | /* FIXME These registers change depending on scaled / unscaled output | ||
470 | We really need to work out what they should be */ | ||
471 | if (window->src_h == window->dst_h){ | ||
472 | reg_2934 = 0x00020000; | ||
473 | reg_293c = 0x00100000; | ||
474 | reg_2944 = 0x00040000; | ||
475 | reg_294c = 0x000b0000; | ||
476 | } | ||
477 | else { | ||
478 | reg_2934 = 0x00000FF0; | ||
479 | reg_293c = 0x00000FF0; | ||
480 | reg_2944 = 0x00000FF0; | ||
481 | reg_294c = 0x00000FF0; | ||
482 | } | ||
483 | |||
484 | /* The first line to be displayed */ | ||
485 | reg_2950 = 0x00010000 + src_y_major_y; | ||
486 | if (window->interlaced_y) reg_2950 += 0x00010000; | ||
487 | reg_2954 = reg_2950 + 1; | ||
488 | |||
489 | reg_2958 = 0x00010000 + (src_y_major_y >> 1); | ||
490 | if (window->interlaced_uv) reg_2958 += 0x00010000; | ||
491 | reg_295c = reg_2958 + 1; | ||
492 | |||
493 | if (itv->yuv_info.decode_height == 480) | ||
494 | reg_289c = 0x011e0017; | ||
495 | else | ||
496 | reg_289c = 0x01500017; | ||
497 | |||
498 | if (window->dst_y < 0) | ||
499 | reg_289c = (reg_289c - ((window->dst_y & ~1)<<15))-(window->dst_y >>1); | ||
500 | else | ||
501 | reg_289c = (reg_289c + ((window->dst_y & ~1)<<15))+(window->dst_y >>1); | ||
502 | |||
503 | /* How much of the source to decode. | ||
504 | Take into account the source offset */ | ||
505 | reg_2960 = ((src_y_minor_y + window->src_h + src_y_major_y) - 1 ) | | ||
506 | ((((src_y_minor_uv + window->src_h + src_y_major_uv) - 1) & ~1) << 15); | ||
507 | |||
508 | /* Calculate correct value for register 2964 */ | ||
509 | if (window->src_h == window->dst_h) | ||
510 | reg_2964 = 1; | ||
511 | else { | ||
512 | reg_2964 = 2 + ((window->dst_h << 1) / window->src_h); | ||
513 | reg_2964 = (reg_2964 >> 1) + (reg_2964 & 1); | ||
514 | } | ||
515 | reg_2968 = (reg_2964 << 16) + reg_2964 + (reg_2964 >> 1); | ||
516 | reg_2964 = (reg_2964 << 16) + reg_2964 + (reg_2964 * 46 / 94); | ||
517 | |||
518 | /* Okay, we've wasted time working out the correct value, | ||
519 | but if we use it, it fouls the the window alignment. | ||
520 | Fudge it to what we want... */ | ||
521 | reg_2964 = 0x00010001 + ((reg_2964 & 0x0000FFFF) - (reg_2964 >> 16)); | ||
522 | reg_2968 = 0x00010001 + ((reg_2968 & 0x0000FFFF) - (reg_2968 >> 16)); | ||
523 | |||
524 | /* Deviate further from what it should be. I find the flicker headache | ||
525 | inducing so try to reduce it slightly. Leave 2968 as-is otherwise | ||
526 | colours foul. */ | ||
527 | if ((reg_2964 != 0x00010001) && (window->dst_h / 2 <= window->src_h)) | ||
528 | reg_2964 = (reg_2964 & 0xFFFF0000) + ((reg_2964 & 0x0000FFFF)/2); | ||
529 | |||
530 | if (!window->interlaced_y) reg_2964 -= 0x00010001; | ||
531 | if (!window->interlaced_uv) reg_2968 -= 0x00010001; | ||
532 | |||
533 | reg_2964 += ((reg_2964_base << 16) | reg_2964_base); | ||
534 | reg_2968 += ((reg_2968_base << 16) | reg_2968_base); | ||
535 | |||
536 | /* Select the vertical filter */ | ||
537 | if (window->src_h == window->dst_h) { | ||
538 | /* An exact size match uses filter 0/1 */ | ||
539 | v_filter_1 = 0; | ||
540 | v_filter_2 = 1; | ||
541 | } | ||
542 | else { | ||
543 | /* Figure out which filter to use */ | ||
544 | v_filter_1 = ((window->src_h << 16) / window->dst_h) >> 15; | ||
545 | v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1); | ||
546 | /* Only an exact size match can use filter 0 */ | ||
547 | if (v_filter_1 == 0) v_filter_1 = 1; | ||
548 | v_filter_2 = v_filter_1; | ||
549 | } | ||
550 | |||
551 | write_reg(reg_2934, 0x02934); | ||
552 | write_reg(reg_293c, 0x0293c); | ||
553 | IVTV_DEBUG_YUV("Update reg 0x2934 %08x->%08x 0x293c %08x->%08x\n",itv->yuv_info.reg_2934, reg_2934, itv->yuv_info.reg_293c, reg_293c); | ||
554 | write_reg(reg_2944, 0x02944); | ||
555 | write_reg(reg_294c, 0x0294c); | ||
556 | IVTV_DEBUG_YUV("Update reg 0x2944 %08x->%08x 0x294c %08x->%08x\n",itv->yuv_info.reg_2944, reg_2944, itv->yuv_info.reg_294c, reg_294c); | ||
557 | |||
558 | /* Ensure 2970 is 0 (does it ever change ?) */ | ||
559 | /* write_reg(0,0x02970); */ | ||
560 | /* IVTV_DEBUG_YUV("Update reg 0x2970 %08x->%08x\n",itv->yuv_info.reg_2970, 0); */ | ||
561 | |||
562 | write_reg(reg_2930, 0x02938); | ||
563 | write_reg(reg_2930, 0x02930); | ||
564 | IVTV_DEBUG_YUV("Update reg 0x2930 %08x->%08x 0x2938 %08x->%08x\n",itv->yuv_info.reg_2930, reg_2930, itv->yuv_info.reg_2938, reg_2930); | ||
565 | |||
566 | write_reg(reg_2928, 0x02928); | ||
567 | write_reg(reg_2928+0x514, 0x0292C); | ||
568 | IVTV_DEBUG_YUV("Update reg 0x2928 %08x->%08x 0x292c %08x->%08x\n",itv->yuv_info.reg_2928, reg_2928, itv->yuv_info.reg_292c, reg_2928+0x514); | ||
569 | |||
570 | write_reg(reg_2920, 0x02920); | ||
571 | write_reg(reg_2920+0x514, 0x02924); | ||
572 | IVTV_DEBUG_YUV("Update reg 0x2920 %08x->%08x 0x2924 %08x->%08x\n",itv->yuv_info.reg_2920, reg_2920, itv->yuv_info.reg_2924, 0x514+reg_2920); | ||
573 | |||
574 | write_reg (reg_2918,0x02918); | ||
575 | write_reg (reg_291c,0x0291C); | ||
576 | IVTV_DEBUG_YUV("Update reg 0x2918 %08x->%08x 0x291C %08x->%08x\n",itv->yuv_info.reg_2918,reg_2918,itv->yuv_info.reg_291c,reg_291c); | ||
577 | |||
578 | write_reg(reg_296c, 0x0296c); | ||
579 | IVTV_DEBUG_YUV("Update reg 0x296c %08x->%08x\n",itv->yuv_info.reg_296c, reg_296c); | ||
580 | |||
581 | write_reg(reg_2940, 0x02948); | ||
582 | write_reg(reg_2940, 0x02940); | ||
583 | IVTV_DEBUG_YUV("Update reg 0x2940 %08x->%08x 0x2948 %08x->%08x\n",itv->yuv_info.reg_2940, reg_2940, itv->yuv_info.reg_2948, reg_2940); | ||
584 | |||
585 | write_reg(reg_2950, 0x02950); | ||
586 | write_reg(reg_2954, 0x02954); | ||
587 | IVTV_DEBUG_YUV("Update reg 0x2950 %08x->%08x 0x2954 %08x->%08x\n",itv->yuv_info.reg_2950, reg_2950, itv->yuv_info.reg_2954, reg_2954); | ||
588 | |||
589 | write_reg(reg_2958, 0x02958); | ||
590 | write_reg(reg_295c, 0x0295C); | ||
591 | IVTV_DEBUG_YUV("Update reg 0x2958 %08x->%08x 0x295C %08x->%08x\n",itv->yuv_info.reg_2958, reg_2958, itv->yuv_info.reg_295c, reg_295c); | ||
592 | |||
593 | write_reg(reg_2960, 0x02960); | ||
594 | IVTV_DEBUG_YUV("Update reg 0x2960 %08x->%08x \n",itv->yuv_info.reg_2960, reg_2960); | ||
595 | |||
596 | write_reg(reg_2964, 0x02964); | ||
597 | write_reg(reg_2968, 0x02968); | ||
598 | IVTV_DEBUG_YUV("Update reg 0x2964 %08x->%08x 0x2968 %08x->%08x\n",itv->yuv_info.reg_2964, reg_2964, itv->yuv_info.reg_2968, reg_2968); | ||
599 | |||
600 | write_reg( reg_289c,0x0289c); | ||
601 | IVTV_DEBUG_YUV("Update reg 0x289c %08x->%08x\n",itv->yuv_info.reg_289c, reg_289c); | ||
602 | |||
603 | /* Only update filter 1 if we really need to */ | ||
604 | if (v_filter_1 != itv->yuv_info.v_filter_1) { | ||
605 | ivtv_yuv_filter (itv,-1,v_filter_1,-1); | ||
606 | itv->yuv_info.v_filter_1 = v_filter_1; | ||
607 | } | ||
608 | |||
609 | /* Only update filter 2 if we really need to */ | ||
610 | if (v_filter_2 != itv->yuv_info.v_filter_2) { | ||
611 | ivtv_yuv_filter (itv,-1,-1,v_filter_2); | ||
612 | itv->yuv_info.v_filter_2 = v_filter_2; | ||
613 | } | ||
614 | |||
615 | itv->yuv_info.frame_interlaced_last = itv->yuv_info.frame_interlaced; | ||
616 | } | ||
617 | |||
618 | /* Modify the supplied coordinate information to fit the visible osd area */ | ||
619 | static u32 ivtv_yuv_window_setup (struct ivtv *itv, struct yuv_frame_info *window) | ||
620 | { | ||
621 | int osd_crop, lace_threshold; | ||
622 | u32 osd_scale; | ||
623 | u32 yuv_update = 0; | ||
624 | |||
625 | lace_threshold = itv->yuv_info.lace_threshold; | ||
626 | if (lace_threshold < 0) | ||
627 | lace_threshold = itv->yuv_info.decode_height - 1; | ||
628 | |||
629 | /* Work out the lace settings */ | ||
630 | switch (itv->yuv_info.lace_mode) { | ||
631 | case IVTV_YUV_MODE_PROGRESSIVE: /* Progressive mode */ | ||
632 | itv->yuv_info.frame_interlaced = 0; | ||
633 | if (window->tru_h < 512 || (window->tru_h > 576 && window->tru_h < 1021)) | ||
634 | window->interlaced_y = 0; | ||
635 | else | ||
636 | window->interlaced_y = 1; | ||
637 | |||
638 | if (window->tru_h < 1021 && (window->dst_h >= window->src_h /2)) | ||
639 | window->interlaced_uv = 0; | ||
640 | else | ||
641 | window->interlaced_uv = 1; | ||
642 | break; | ||
643 | |||
644 | case IVTV_YUV_MODE_AUTO: | ||
645 | if (window->tru_h <= lace_threshold || window->tru_h > 576 || window->tru_w > 720){ | ||
646 | itv->yuv_info.frame_interlaced = 0; | ||
647 | if ((window->tru_h < 512) || | ||
648 | (window->tru_h > 576 && window->tru_h < 1021) || | ||
649 | (window->tru_w > 720 && window->tru_h < 1021)) | ||
650 | window->interlaced_y = 0; | ||
651 | else | ||
652 | window->interlaced_y = 1; | ||
653 | |||
654 | if (window->tru_h < 1021 && (window->dst_h >= window->src_h /2)) | ||
655 | window->interlaced_uv = 0; | ||
656 | else | ||
657 | window->interlaced_uv = 1; | ||
658 | } | ||
659 | else { | ||
660 | itv->yuv_info.frame_interlaced = 1; | ||
661 | window->interlaced_y = 1; | ||
662 | window->interlaced_uv = 1; | ||
663 | } | ||
664 | break; | ||
665 | |||
666 | case IVTV_YUV_MODE_INTERLACED: /* Interlace mode */ | ||
667 | default: | ||
668 | itv->yuv_info.frame_interlaced = 1; | ||
669 | window->interlaced_y = 1; | ||
670 | window->interlaced_uv = 1; | ||
671 | break; | ||
672 | } | ||
673 | |||
674 | /* Sorry, but no negative coords for src */ | ||
675 | if (window->src_x < 0) window->src_x = 0; | ||
676 | if (window->src_y < 0) window->src_y = 0; | ||
677 | |||
678 | /* Can only reduce width down to 1/4 original size */ | ||
679 | if ((osd_crop = window->src_w - ( 4 * window->dst_w )) > 0) { | ||
680 | window->src_x += osd_crop / 2; | ||
681 | window->src_w = (window->src_w - osd_crop) & ~3; | ||
682 | window->dst_w = window->src_w / 4; | ||
683 | window->dst_w += window->dst_w & 1; | ||
684 | } | ||
685 | |||
686 | /* Can only reduce height down to 1/4 original size */ | ||
687 | if (window->src_h / window->dst_h >= 2) { | ||
688 | /* Overflow may be because we're running progressive, so force mode switch */ | ||
689 | window->interlaced_y = 1; | ||
690 | /* Make sure we're still within limits for interlace */ | ||
691 | if ((osd_crop = window->src_h - ( 4 * window->dst_h )) > 0) { | ||
692 | /* If we reach here we'll have to force the height. */ | ||
693 | window->src_y += osd_crop / 2; | ||
694 | window->src_h = (window->src_h - osd_crop) & ~3; | ||
695 | window->dst_h = window->src_h / 4; | ||
696 | window->dst_h += window->dst_h & 1; | ||
697 | } | ||
698 | } | ||
699 | |||
700 | /* If there's nothing to safe to display, we may as well stop now */ | ||
701 | if ((int)window->dst_w <= 2 || (int)window->dst_h <= 2 || (int)window->src_w <= 2 || (int)window->src_h <= 2) { | ||
702 | return 0; | ||
703 | } | ||
704 | |||
705 | /* Ensure video remains inside OSD area */ | ||
706 | osd_scale = (window->src_h << 16) / window->dst_h; | ||
707 | |||
708 | if ((osd_crop = window->pan_y - window->dst_y) > 0) { | ||
709 | /* Falls off the upper edge - crop */ | ||
710 | window->src_y += (osd_scale * osd_crop) >> 16; | ||
711 | window->src_h -= (osd_scale * osd_crop) >> 16; | ||
712 | window->dst_h -= osd_crop; | ||
713 | window->dst_y = 0; | ||
714 | } | ||
715 | else { | ||
716 | window->dst_y -= window->pan_y; | ||
717 | } | ||
718 | |||
719 | if ((osd_crop = window->dst_h + window->dst_y - window->vis_h) > 0) { | ||
720 | /* Falls off the lower edge - crop */ | ||
721 | window->dst_h -= osd_crop; | ||
722 | window->src_h -= (osd_scale * osd_crop) >> 16; | ||
723 | } | ||
724 | |||
725 | osd_scale = (window->src_w << 16) / window->dst_w; | ||
726 | |||
727 | if ((osd_crop = window->pan_x - window->dst_x) > 0) { | ||
728 | /* Fall off the left edge - crop */ | ||
729 | window->src_x += (osd_scale * osd_crop) >> 16; | ||
730 | window->src_w -= (osd_scale * osd_crop) >> 16; | ||
731 | window->dst_w -= osd_crop; | ||
732 | window->dst_x = 0; | ||
733 | } | ||
734 | else { | ||
735 | window->dst_x -= window->pan_x; | ||
736 | } | ||
737 | |||
738 | if ((osd_crop = window->dst_w + window->dst_x - window->vis_w) > 0) { | ||
739 | /* Falls off the right edge - crop */ | ||
740 | window->dst_w -= osd_crop; | ||
741 | window->src_w -= (osd_scale * osd_crop) >> 16; | ||
742 | } | ||
743 | |||
744 | /* The OSD can be moved. Track to it */ | ||
745 | window->dst_x += itv->yuv_info.osd_x_offset; | ||
746 | window->dst_y += itv->yuv_info.osd_y_offset; | ||
747 | |||
748 | /* Width & height for both src & dst must be even. | ||
749 | Same for coordinates. */ | ||
750 | window->dst_w &= ~1; | ||
751 | window->dst_x &= ~1; | ||
752 | |||
753 | window->src_w += window->src_x & 1; | ||
754 | window->src_x &= ~1; | ||
755 | |||
756 | window->src_w &= ~1; | ||
757 | window->dst_w &= ~1; | ||
758 | |||
759 | window->dst_h &= ~1; | ||
760 | window->dst_y &= ~1; | ||
761 | |||
762 | window->src_h += window->src_y & 1; | ||
763 | window->src_y &= ~1; | ||
764 | |||
765 | window->src_h &= ~1; | ||
766 | window->dst_h &= ~1; | ||
767 | |||
768 | /* Due to rounding, we may have reduced the output size to <1/4 of the source | ||
769 | Check again, but this time just resize. Don't change source coordinates */ | ||
770 | if (window->dst_w < window->src_w / 4) { | ||
771 | window->src_w &= ~3; | ||
772 | window->dst_w = window->src_w / 4; | ||
773 | window->dst_w += window->dst_w & 1; | ||
774 | } | ||
775 | if (window->dst_h < window->src_h / 4) { | ||
776 | window->src_h &= ~3; | ||
777 | window->dst_h = window->src_h / 4; | ||
778 | window->dst_h += window->dst_h & 1; | ||
779 | } | ||
780 | |||
781 | /* Check again. If there's nothing to safe to display, stop now */ | ||
782 | if ((int)window->dst_w <= 2 || (int)window->dst_h <= 2 || (int)window->src_w <= 2 || (int)window->src_h <= 2) { | ||
783 | return 0; | ||
784 | } | ||
785 | |||
786 | /* Both x offset & width are linked, so they have to be done together */ | ||
787 | if ((itv->yuv_info.old_frame_info.dst_w != window->dst_w) || | ||
788 | (itv->yuv_info.old_frame_info.src_w != window->src_w) || | ||
789 | (itv->yuv_info.old_frame_info.dst_x != window->dst_x) || | ||
790 | (itv->yuv_info.old_frame_info.src_x != window->src_x) || | ||
791 | (itv->yuv_info.old_frame_info.pan_x != window->pan_x) || | ||
792 | (itv->yuv_info.old_frame_info.vis_w != window->vis_w)) { | ||
793 | yuv_update |= IVTV_YUV_UPDATE_HORIZONTAL; | ||
794 | } | ||
795 | |||
796 | if ((itv->yuv_info.old_frame_info.src_h != window->src_h) || | ||
797 | (itv->yuv_info.old_frame_info.dst_h != window->dst_h) || | ||
798 | (itv->yuv_info.old_frame_info.dst_y != window->dst_y) || | ||
799 | (itv->yuv_info.old_frame_info.src_y != window->src_y) || | ||
800 | (itv->yuv_info.old_frame_info.pan_y != window->pan_y) || | ||
801 | (itv->yuv_info.old_frame_info.vis_h != window->vis_h) || | ||
802 | (itv->yuv_info.old_frame_info.interlaced_y != window->interlaced_y) || | ||
803 | (itv->yuv_info.old_frame_info.interlaced_uv != window->interlaced_uv)) { | ||
804 | yuv_update |= IVTV_YUV_UPDATE_VERTICAL; | ||
805 | } | ||
806 | |||
807 | return yuv_update; | ||
808 | } | ||
809 | |||
810 | /* Update the scaling register to the requested value */ | ||
811 | void ivtv_yuv_work_handler (struct ivtv *itv) | ||
812 | { | ||
813 | struct yuv_frame_info window; | ||
814 | u32 yuv_update; | ||
815 | |||
816 | int frame = itv->yuv_info.update_frame; | ||
817 | |||
818 | /* IVTV_DEBUG_YUV("Update yuv registers for frame %d\n",frame); */ | ||
819 | memcpy(&window, &itv->yuv_info.new_frame_info[frame], sizeof (window)); | ||
820 | |||
821 | /* Update the osd pan info */ | ||
822 | window.pan_x = itv->yuv_info.osd_x_pan; | ||
823 | window.pan_y = itv->yuv_info.osd_y_pan; | ||
824 | window.vis_w = itv->yuv_info.osd_vis_w; | ||
825 | window.vis_h = itv->yuv_info.osd_vis_h; | ||
826 | |||
827 | /* Calculate the display window coordinates. Exit if nothing left */ | ||
828 | if (!(yuv_update = ivtv_yuv_window_setup (itv, &window))) | ||
829 | return; | ||
830 | |||
831 | /* Update horizontal settings */ | ||
832 | if (yuv_update & IVTV_YUV_UPDATE_HORIZONTAL) | ||
833 | ivtv_yuv_handle_horizontal(itv, &window); | ||
834 | |||
835 | if (yuv_update & IVTV_YUV_UPDATE_VERTICAL) | ||
836 | ivtv_yuv_handle_vertical(itv, &window); | ||
837 | |||
838 | memcpy(&itv->yuv_info.old_frame_info, &window, sizeof (itv->yuv_info.old_frame_info)); | ||
839 | } | ||
840 | |||
841 | static void ivtv_yuv_init (struct ivtv *itv) | ||
842 | { | ||
843 | IVTV_DEBUG_YUV("ivtv_yuv_init\n"); | ||
844 | |||
845 | /* Take a snapshot of the current register settings */ | ||
846 | itv->yuv_info.reg_2834 = read_reg(0x02834); | ||
847 | itv->yuv_info.reg_2838 = read_reg(0x02838); | ||
848 | itv->yuv_info.reg_283c = read_reg(0x0283c); | ||
849 | itv->yuv_info.reg_2840 = read_reg(0x02840); | ||
850 | itv->yuv_info.reg_2844 = read_reg(0x02844); | ||
851 | itv->yuv_info.reg_2848 = read_reg(0x02848); | ||
852 | itv->yuv_info.reg_2854 = read_reg(0x02854); | ||
853 | itv->yuv_info.reg_285c = read_reg(0x0285c); | ||
854 | itv->yuv_info.reg_2864 = read_reg(0x02864); | ||
855 | itv->yuv_info.reg_2870 = read_reg(0x02870); | ||
856 | itv->yuv_info.reg_2874 = read_reg(0x02874); | ||
857 | itv->yuv_info.reg_2898 = read_reg(0x02898); | ||
858 | itv->yuv_info.reg_2890 = read_reg(0x02890); | ||
859 | |||
860 | itv->yuv_info.reg_289c = read_reg(0x0289c); | ||
861 | itv->yuv_info.reg_2918 = read_reg(0x02918); | ||
862 | itv->yuv_info.reg_291c = read_reg(0x0291c); | ||
863 | itv->yuv_info.reg_2920 = read_reg(0x02920); | ||
864 | itv->yuv_info.reg_2924 = read_reg(0x02924); | ||
865 | itv->yuv_info.reg_2928 = read_reg(0x02928); | ||
866 | itv->yuv_info.reg_292c = read_reg(0x0292c); | ||
867 | itv->yuv_info.reg_2930 = read_reg(0x02930); | ||
868 | itv->yuv_info.reg_2934 = read_reg(0x02934); | ||
869 | itv->yuv_info.reg_2938 = read_reg(0x02938); | ||
870 | itv->yuv_info.reg_293c = read_reg(0x0293c); | ||
871 | itv->yuv_info.reg_2940 = read_reg(0x02940); | ||
872 | itv->yuv_info.reg_2944 = read_reg(0x02944); | ||
873 | itv->yuv_info.reg_2948 = read_reg(0x02948); | ||
874 | itv->yuv_info.reg_294c = read_reg(0x0294c); | ||
875 | itv->yuv_info.reg_2950 = read_reg(0x02950); | ||
876 | itv->yuv_info.reg_2954 = read_reg(0x02954); | ||
877 | itv->yuv_info.reg_2958 = read_reg(0x02958); | ||
878 | itv->yuv_info.reg_295c = read_reg(0x0295c); | ||
879 | itv->yuv_info.reg_2960 = read_reg(0x02960); | ||
880 | itv->yuv_info.reg_2964 = read_reg(0x02964); | ||
881 | itv->yuv_info.reg_2968 = read_reg(0x02968); | ||
882 | itv->yuv_info.reg_296c = read_reg(0x0296c); | ||
883 | itv->yuv_info.reg_2970 = read_reg(0x02970); | ||
884 | |||
885 | itv->yuv_info.v_filter_1 = -1; | ||
886 | itv->yuv_info.v_filter_2 = -1; | ||
887 | itv->yuv_info.h_filter = -1; | ||
888 | |||
889 | /* Set some valid size info */ | ||
890 | itv->yuv_info.osd_x_offset = read_reg(0x02a04) & 0x00000FFF; | ||
891 | itv->yuv_info.osd_y_offset = (read_reg(0x02a04) >> 16) & 0x00000FFF; | ||
892 | |||
893 | /* Bit 2 of reg 2878 indicates current decoder output format | ||
894 | 0 : NTSC 1 : PAL */ | ||
895 | if (read_reg(0x2878) & 4) | ||
896 | itv->yuv_info.decode_height = 576; | ||
897 | else | ||
898 | itv->yuv_info.decode_height = 480; | ||
899 | |||
900 | /* If no visible size set, assume full size */ | ||
901 | if (!itv->yuv_info.osd_vis_w) itv->yuv_info.osd_vis_w = 720 - itv->yuv_info.osd_x_offset; | ||
902 | if (!itv->yuv_info.osd_vis_h) itv->yuv_info.osd_vis_h = itv->yuv_info.decode_height - itv->yuv_info.osd_y_offset; | ||
903 | |||
904 | /* We need a buffer for blanking when Y plane is offset - non-fatal if we can't get one */ | ||
905 | itv->yuv_info.blanking_ptr = kzalloc(720*16,GFP_KERNEL); | ||
906 | if (itv->yuv_info.blanking_ptr) { | ||
907 | itv->yuv_info.blanking_dmaptr = pci_map_single(itv->dev, itv->yuv_info.blanking_ptr, 720*16, PCI_DMA_TODEVICE); | ||
908 | } | ||
909 | else { | ||
910 | itv->yuv_info.blanking_dmaptr = 0; | ||
911 | IVTV_DEBUG_WARN ("Failed to allocate yuv blanking buffer\n"); | ||
912 | } | ||
913 | |||
914 | IVTV_DEBUG_WARN("Enable video output\n"); | ||
915 | write_reg_sync(0x00108080, 0x2898); | ||
916 | |||
917 | /* Enable YUV decoder output */ | ||
918 | write_reg_sync(0x01, IVTV_REG_VDM); | ||
919 | |||
920 | set_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags); | ||
921 | atomic_set(&itv->yuv_info.next_dma_frame,0); | ||
922 | } | ||
923 | |||
924 | int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args) | ||
925 | { | ||
926 | DEFINE_WAIT(wait); | ||
927 | int rc = 0; | ||
928 | int got_sig = 0; | ||
929 | int frame, next_fill_frame, last_fill_frame; | ||
930 | |||
931 | IVTV_DEBUG_INFO("yuv_prep_frame\n"); | ||
932 | |||
933 | if (atomic_read(&itv->yuv_info.next_dma_frame) == -1) ivtv_yuv_init(itv); | ||
934 | |||
935 | frame = atomic_read(&itv->yuv_info.next_fill_frame); | ||
936 | next_fill_frame = (frame + 1) & 0x3; | ||
937 | last_fill_frame = (atomic_read(&itv->yuv_info.next_dma_frame)+1) & 0x3; | ||
938 | |||
939 | if (next_fill_frame != last_fill_frame && last_fill_frame != frame) { | ||
940 | /* Buffers are full - Overwrite the last frame */ | ||
941 | next_fill_frame = frame; | ||
942 | frame = (frame - 1) & 3; | ||
943 | } | ||
944 | |||
945 | /* Take a snapshot of the yuv coordinate information */ | ||
946 | itv->yuv_info.new_frame_info[frame].src_x = args->src.left; | ||
947 | itv->yuv_info.new_frame_info[frame].src_y = args->src.top; | ||
948 | itv->yuv_info.new_frame_info[frame].src_w = args->src.width; | ||
949 | itv->yuv_info.new_frame_info[frame].src_h = args->src.height; | ||
950 | itv->yuv_info.new_frame_info[frame].dst_x = args->dst.left; | ||
951 | itv->yuv_info.new_frame_info[frame].dst_y = args->dst.top; | ||
952 | itv->yuv_info.new_frame_info[frame].dst_w = args->dst.width; | ||
953 | itv->yuv_info.new_frame_info[frame].dst_h = args->dst.height; | ||
954 | itv->yuv_info.new_frame_info[frame].tru_x = args->dst.left; | ||
955 | itv->yuv_info.new_frame_info[frame].tru_w = args->src_width; | ||
956 | itv->yuv_info.new_frame_info[frame].tru_h = args->src_height; | ||
957 | |||
958 | /* Are we going to offset the Y plane */ | ||
959 | if (args->src.height + args->src.top < 512-16) | ||
960 | itv->yuv_info.new_frame_info[frame].offset_y = 1; | ||
961 | else | ||
962 | itv->yuv_info.new_frame_info[frame].offset_y = 0; | ||
963 | |||
964 | /* Snapshot the osd pan info */ | ||
965 | itv->yuv_info.new_frame_info[frame].pan_x = itv->yuv_info.osd_x_pan; | ||
966 | itv->yuv_info.new_frame_info[frame].pan_y = itv->yuv_info.osd_y_pan; | ||
967 | itv->yuv_info.new_frame_info[frame].vis_w = itv->yuv_info.osd_vis_w; | ||
968 | itv->yuv_info.new_frame_info[frame].vis_h = itv->yuv_info.osd_vis_h; | ||
969 | |||
970 | itv->yuv_info.new_frame_info[frame].update = 0; | ||
971 | itv->yuv_info.new_frame_info[frame].interlaced_y = 0; | ||
972 | itv->yuv_info.new_frame_info[frame].interlaced_uv = 0; | ||
973 | |||
974 | if (memcmp (&itv->yuv_info.old_frame_info_args, &itv->yuv_info.new_frame_info[frame], | ||
975 | sizeof (itv->yuv_info.new_frame_info[frame]))) { | ||
976 | memcpy(&itv->yuv_info.old_frame_info_args, &itv->yuv_info.new_frame_info[frame], sizeof (itv->yuv_info.old_frame_info_args)); | ||
977 | itv->yuv_info.new_frame_info[frame].update = 1; | ||
978 | /* IVTV_DEBUG_YUV ("Requesting register update for frame %d\n",frame); */ | ||
979 | } | ||
980 | |||
981 | /* DMA the frame */ | ||
982 | mutex_lock(&itv->udma.lock); | ||
983 | |||
984 | if ((rc = ivtv_yuv_prep_user_dma(itv, &itv->udma, args)) != 0) { | ||
985 | mutex_unlock(&itv->udma.lock); | ||
986 | return rc; | ||
987 | } | ||
988 | |||
989 | ivtv_udma_prepare(itv); | ||
990 | prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE); | ||
991 | /* if no UDMA is pending and no UDMA is in progress, then the DMA | ||
992 | is finished */ | ||
993 | while (itv->i_flags & (IVTV_F_I_UDMA_PENDING | IVTV_F_I_UDMA)) { | ||
994 | /* don't interrupt if the DMA is in progress but break off | ||
995 | a still pending DMA. */ | ||
996 | got_sig = signal_pending(current); | ||
997 | if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags)) | ||
998 | break; | ||
999 | got_sig = 0; | ||
1000 | schedule(); | ||
1001 | } | ||
1002 | finish_wait(&itv->dma_waitq, &wait); | ||
1003 | |||
1004 | /* Unmap Last DMA Xfer */ | ||
1005 | ivtv_udma_unmap(itv); | ||
1006 | |||
1007 | if (got_sig) { | ||
1008 | IVTV_DEBUG_INFO("User stopped YUV UDMA\n"); | ||
1009 | mutex_unlock(&itv->udma.lock); | ||
1010 | return -EINTR; | ||
1011 | } | ||
1012 | |||
1013 | atomic_set(&itv->yuv_info.next_fill_frame, next_fill_frame); | ||
1014 | |||
1015 | mutex_unlock(&itv->udma.lock); | ||
1016 | return rc; | ||
1017 | } | ||
1018 | |||
1019 | void ivtv_yuv_close(struct ivtv *itv) | ||
1020 | { | ||
1021 | int h_filter, v_filter_1, v_filter_2; | ||
1022 | |||
1023 | IVTV_DEBUG_YUV("ivtv_yuv_close\n"); | ||
1024 | ivtv_waitq(&itv->vsync_waitq); | ||
1025 | |||
1026 | atomic_set(&itv->yuv_info.next_dma_frame, -1); | ||
1027 | atomic_set(&itv->yuv_info.next_fill_frame, 0); | ||
1028 | |||
1029 | /* Reset registers we have changed so mpeg playback works */ | ||
1030 | |||
1031 | /* If we fully restore this register, the display may remain active. | ||
1032 | Restore, but set one bit to blank the video. Firmware will always | ||
1033 | clear this bit when needed, so not a problem. */ | ||
1034 | write_reg(itv->yuv_info.reg_2898 | 0x01000000, 0x2898); | ||
1035 | |||
1036 | write_reg(itv->yuv_info.reg_2834, 0x02834); | ||
1037 | write_reg(itv->yuv_info.reg_2838, 0x02838); | ||
1038 | write_reg(itv->yuv_info.reg_283c, 0x0283c); | ||
1039 | write_reg(itv->yuv_info.reg_2840, 0x02840); | ||
1040 | write_reg(itv->yuv_info.reg_2844, 0x02844); | ||
1041 | write_reg(itv->yuv_info.reg_2848, 0x02848); | ||
1042 | write_reg(itv->yuv_info.reg_2854, 0x02854); | ||
1043 | write_reg(itv->yuv_info.reg_285c, 0x0285c); | ||
1044 | write_reg(itv->yuv_info.reg_2864, 0x02864); | ||
1045 | write_reg(itv->yuv_info.reg_2870, 0x02870); | ||
1046 | write_reg(itv->yuv_info.reg_2874, 0x02874); | ||
1047 | write_reg(itv->yuv_info.reg_2890, 0x02890); | ||
1048 | write_reg(itv->yuv_info.reg_289c, 0x0289c); | ||
1049 | |||
1050 | write_reg(itv->yuv_info.reg_2918, 0x02918); | ||
1051 | write_reg(itv->yuv_info.reg_291c, 0x0291c); | ||
1052 | write_reg(itv->yuv_info.reg_2920, 0x02920); | ||
1053 | write_reg(itv->yuv_info.reg_2924, 0x02924); | ||
1054 | write_reg(itv->yuv_info.reg_2928, 0x02928); | ||
1055 | write_reg(itv->yuv_info.reg_292c, 0x0292c); | ||
1056 | write_reg(itv->yuv_info.reg_2930, 0x02930); | ||
1057 | write_reg(itv->yuv_info.reg_2934, 0x02934); | ||
1058 | write_reg(itv->yuv_info.reg_2938, 0x02938); | ||
1059 | write_reg(itv->yuv_info.reg_293c, 0x0293c); | ||
1060 | write_reg(itv->yuv_info.reg_2940, 0x02940); | ||
1061 | write_reg(itv->yuv_info.reg_2944, 0x02944); | ||
1062 | write_reg(itv->yuv_info.reg_2948, 0x02948); | ||
1063 | write_reg(itv->yuv_info.reg_294c, 0x0294c); | ||
1064 | write_reg(itv->yuv_info.reg_2950, 0x02950); | ||
1065 | write_reg(itv->yuv_info.reg_2954, 0x02954); | ||
1066 | write_reg(itv->yuv_info.reg_2958, 0x02958); | ||
1067 | write_reg(itv->yuv_info.reg_295c, 0x0295c); | ||
1068 | write_reg(itv->yuv_info.reg_2960, 0x02960); | ||
1069 | write_reg(itv->yuv_info.reg_2964, 0x02964); | ||
1070 | write_reg(itv->yuv_info.reg_2968, 0x02968); | ||
1071 | write_reg(itv->yuv_info.reg_296c, 0x0296c); | ||
1072 | write_reg(itv->yuv_info.reg_2970, 0x02970); | ||
1073 | |||
1074 | /* Prepare to restore filters */ | ||
1075 | |||
1076 | /* First the horizontal filter */ | ||
1077 | if ((itv->yuv_info.reg_2834 & 0x0000FFFF) == (itv->yuv_info.reg_2834 >> 16)) { | ||
1078 | /* An exact size match uses filter 0 */ | ||
1079 | h_filter = 0; | ||
1080 | } | ||
1081 | else { | ||
1082 | /* Figure out which filter to use */ | ||
1083 | h_filter = ((itv->yuv_info.reg_2834 << 16) / (itv->yuv_info.reg_2834 >> 16)) >> 15; | ||
1084 | h_filter = (h_filter >> 1) + (h_filter & 1); | ||
1085 | /* Only an exact size match can use filter 0. */ | ||
1086 | if (h_filter < 1) h_filter = 1; | ||
1087 | } | ||
1088 | |||
1089 | /* Now the vertical filter */ | ||
1090 | if ((itv->yuv_info.reg_2918 & 0x0000FFFF) == (itv->yuv_info.reg_2918 >> 16)) { | ||
1091 | /* An exact size match uses filter 0/1 */ | ||
1092 | v_filter_1 = 0; | ||
1093 | v_filter_2 = 1; | ||
1094 | } | ||
1095 | else { | ||
1096 | /* Figure out which filter to use */ | ||
1097 | v_filter_1 = ((itv->yuv_info.reg_2918 << 16) / (itv->yuv_info.reg_2918 >> 16)) >> 15; | ||
1098 | v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1); | ||
1099 | /* Only an exact size match can use filter 0 */ | ||
1100 | if (v_filter_1 == 0) v_filter_1 = 1; | ||
1101 | v_filter_2 = v_filter_1; | ||
1102 | } | ||
1103 | |||
1104 | /* Now restore the filters */ | ||
1105 | ivtv_yuv_filter (itv,h_filter,v_filter_1,v_filter_2); | ||
1106 | |||
1107 | /* and clear a few registers */ | ||
1108 | write_reg(0, 0x02814); | ||
1109 | write_reg(0, 0x0282c); | ||
1110 | write_reg(0, 0x02904); | ||
1111 | write_reg(0, 0x02910); | ||
1112 | |||
1113 | /* Release the blanking buffer */ | ||
1114 | if (itv->yuv_info.blanking_ptr) { | ||
1115 | kfree (itv->yuv_info.blanking_ptr); | ||
1116 | itv->yuv_info.blanking_ptr = NULL; | ||
1117 | pci_unmap_single(itv->dev, itv->yuv_info.blanking_dmaptr, 720*16, PCI_DMA_TODEVICE); | ||
1118 | } | ||
1119 | |||
1120 | /* Invalidate the old dimension information */ | ||
1121 | itv->yuv_info.old_frame_info.src_w = 0; | ||
1122 | itv->yuv_info.old_frame_info.src_h = 0; | ||
1123 | itv->yuv_info.old_frame_info_args.src_w = 0; | ||
1124 | itv->yuv_info.old_frame_info_args.src_h = 0; | ||
1125 | |||
1126 | /* All done. */ | ||
1127 | clear_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags); | ||
1128 | } | ||
1129 | |||
diff --git a/drivers/media/video/ivtv/ivtv-yuv.h b/drivers/media/video/ivtv/ivtv-yuv.h new file mode 100644 index 000000000000..88972d3f77c4 --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-yuv.h | |||
@@ -0,0 +1,24 @@ | |||
1 | /* | ||
2 | yuv support | ||
3 | |||
4 | Copyright (C) 2007 Ian Armstrong <ian@iarmst.demon.co.uk> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | int ivtv_yuv_filter_check(struct ivtv *itv); | ||
22 | int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args); | ||
23 | void ivtv_yuv_close(struct ivtv *itv); | ||
24 | void ivtv_yuv_work_handler (struct ivtv *itv); | ||
diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c index ba1af3c8525e..3bb7d6634862 100644 --- a/drivers/media/video/msp3400-driver.c +++ b/drivers/media/video/msp3400-driver.c | |||
@@ -773,6 +773,9 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) | |||
773 | break; | 773 | break; |
774 | } | 774 | } |
775 | 775 | ||
776 | case VIDIOC_G_CHIP_IDENT: | ||
777 | return v4l2_chip_ident_i2c_client(client, arg, state->ident, (state->rev1 << 16) | state->rev2); | ||
778 | |||
776 | default: | 779 | default: |
777 | /* unknown */ | 780 | /* unknown */ |
778 | return -EINVAL; | 781 | return -EINVAL; |
@@ -872,6 +875,8 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind) | |||
872 | snprintf(client->name, sizeof(client->name), "MSP%d4%02d%c-%c%d", | 875 | snprintf(client->name, sizeof(client->name), "MSP%d4%02d%c-%c%d", |
873 | msp_family, msp_product, | 876 | msp_family, msp_product, |
874 | msp_revision, msp_hard, msp_rom); | 877 | msp_revision, msp_hard, msp_rom); |
878 | /* Rev B=2, C=3, D=4, G=7 */ | ||
879 | state->ident = msp_family * 10000 + 4000 + msp_product * 10 + msp_revision - '@'; | ||
875 | 880 | ||
876 | /* Has NICAM support: all mspx41x and mspx45x products have NICAM */ | 881 | /* Has NICAM support: all mspx41x and mspx45x products have NICAM */ |
877 | state->has_nicam = msp_prod_hi == 1 || msp_prod_hi == 5; | 882 | state->has_nicam = msp_prod_hi == 1 || msp_prod_hi == 5; |
diff --git a/drivers/media/video/msp3400-driver.h b/drivers/media/video/msp3400-driver.h index 7531efa1615e..ab69a290e5dc 100644 --- a/drivers/media/video/msp3400-driver.h +++ b/drivers/media/video/msp3400-driver.h | |||
@@ -50,6 +50,7 @@ extern int msp_stereo_thresh; | |||
50 | 50 | ||
51 | struct msp_state { | 51 | struct msp_state { |
52 | int rev1, rev2; | 52 | int rev1, rev2; |
53 | int ident; | ||
53 | u8 has_nicam; | 54 | u8 has_nicam; |
54 | u8 has_radio; | 55 | u8 has_radio; |
55 | u8 has_headphones; | 56 | u8 has_headphones; |
diff --git a/drivers/media/video/ov7670.c b/drivers/media/video/ov7670.c index 5ed0adc4ca26..03bc369a9e49 100644 --- a/drivers/media/video/ov7670.c +++ b/drivers/media/video/ov7670.c | |||
@@ -5,6 +5,8 @@ | |||
5 | * by Jonathan Corbet with substantial inspiration from Mark | 5 | * by Jonathan Corbet with substantial inspiration from Mark |
6 | * McClelland's ovcamchip code. | 6 | * McClelland's ovcamchip code. |
7 | * | 7 | * |
8 | * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net> | ||
9 | * | ||
8 | * This file may be distributed under the terms of the GNU General | 10 | * This file may be distributed under the terms of the GNU General |
9 | * Public License, version 2. | 11 | * Public License, version 2. |
10 | */ | 12 | */ |
@@ -15,6 +17,7 @@ | |||
15 | #include <linux/delay.h> | 17 | #include <linux/delay.h> |
16 | #include <linux/videodev.h> | 18 | #include <linux/videodev.h> |
17 | #include <media/v4l2-common.h> | 19 | #include <media/v4l2-common.h> |
20 | #include <media/v4l2-chip-ident.h> | ||
18 | #include <linux/i2c.h> | 21 | #include <linux/i2c.h> |
19 | 22 | ||
20 | 23 | ||
@@ -162,6 +165,10 @@ MODULE_LICENSE("GPL"); | |||
162 | 165 | ||
163 | #define REG_GFIX 0x69 /* Fix gain control */ | 166 | #define REG_GFIX 0x69 /* Fix gain control */ |
164 | 167 | ||
168 | #define REG_REG76 0x76 /* OV's name */ | ||
169 | #define R76_BLKPCOR 0x80 /* Black pixel correction enable */ | ||
170 | #define R76_WHTPCOR 0x40 /* White pixel correction enable */ | ||
171 | |||
165 | #define REG_RGB444 0x8c /* RGB 444 control */ | 172 | #define REG_RGB444 0x8c /* RGB 444 control */ |
166 | #define R444_ENABLE 0x02 /* Turn on RGB444, overrides 5x5 */ | 173 | #define R444_ENABLE 0x02 /* Turn on RGB444, overrides 5x5 */ |
167 | #define R444_RGBX 0x01 /* Empty nibble at end */ | 174 | #define R444_RGBX 0x01 /* Empty nibble at end */ |
@@ -255,7 +262,7 @@ static struct regval_list ov7670_default_regs[] = { | |||
255 | 262 | ||
256 | /* Almost all of these are magic "reserved" values. */ | 263 | /* Almost all of these are magic "reserved" values. */ |
257 | { REG_COM5, 0x61 }, { REG_COM6, 0x4b }, | 264 | { REG_COM5, 0x61 }, { REG_COM6, 0x4b }, |
258 | { 0x16, 0x02 }, { REG_MVFP, 0x07|MVFP_MIRROR }, | 265 | { 0x16, 0x02 }, { REG_MVFP, 0x07 }, |
259 | { 0x21, 0x02 }, { 0x22, 0x91 }, | 266 | { 0x21, 0x02 }, { 0x22, 0x91 }, |
260 | { 0x29, 0x07 }, { 0x33, 0x0b }, | 267 | { 0x29, 0x07 }, { 0x33, 0x0b }, |
261 | { 0x35, 0x0b }, { 0x37, 0x1d }, | 268 | { 0x35, 0x0b }, { 0x37, 0x1d }, |
@@ -380,6 +387,13 @@ static struct regval_list ov7670_fmt_rgb444[] = { | |||
380 | { 0xff, 0xff }, | 387 | { 0xff, 0xff }, |
381 | }; | 388 | }; |
382 | 389 | ||
390 | static struct regval_list ov7670_fmt_raw[] = { | ||
391 | { REG_COM7, COM7_BAYER }, | ||
392 | { REG_COM13, 0x08 }, /* No gamma, magic rsvd bit */ | ||
393 | { REG_COM16, 0x3d }, /* Edge enhancement, denoise */ | ||
394 | { REG_REG76, 0xe1 }, /* Pix correction, magic rsvd */ | ||
395 | { 0xff, 0xff }, | ||
396 | }; | ||
383 | 397 | ||
384 | 398 | ||
385 | 399 | ||
@@ -483,32 +497,39 @@ static struct ov7670_format_struct { | |||
483 | __u32 pixelformat; | 497 | __u32 pixelformat; |
484 | struct regval_list *regs; | 498 | struct regval_list *regs; |
485 | int cmatrix[CMATRIX_LEN]; | 499 | int cmatrix[CMATRIX_LEN]; |
500 | int bpp; /* Bytes per pixel */ | ||
486 | } ov7670_formats[] = { | 501 | } ov7670_formats[] = { |
487 | { | 502 | { |
488 | .desc = "YUYV 4:2:2", | 503 | .desc = "YUYV 4:2:2", |
489 | .pixelformat = V4L2_PIX_FMT_YUYV, | 504 | .pixelformat = V4L2_PIX_FMT_YUYV, |
490 | .regs = ov7670_fmt_yuv422, | 505 | .regs = ov7670_fmt_yuv422, |
491 | .cmatrix = { 128, -128, 0, -34, -94, 128 }, | 506 | .cmatrix = { 128, -128, 0, -34, -94, 128 }, |
507 | .bpp = 2, | ||
492 | }, | 508 | }, |
493 | { | 509 | { |
494 | .desc = "RGB 444", | 510 | .desc = "RGB 444", |
495 | .pixelformat = V4L2_PIX_FMT_RGB444, | 511 | .pixelformat = V4L2_PIX_FMT_RGB444, |
496 | .regs = ov7670_fmt_rgb444, | 512 | .regs = ov7670_fmt_rgb444, |
497 | .cmatrix = { 179, -179, 0, -61, -176, 228 }, | 513 | .cmatrix = { 179, -179, 0, -61, -176, 228 }, |
514 | .bpp = 2, | ||
498 | }, | 515 | }, |
499 | { | 516 | { |
500 | .desc = "RGB 565", | 517 | .desc = "RGB 565", |
501 | .pixelformat = V4L2_PIX_FMT_RGB565, | 518 | .pixelformat = V4L2_PIX_FMT_RGB565, |
502 | .regs = ov7670_fmt_rgb565, | 519 | .regs = ov7670_fmt_rgb565, |
503 | .cmatrix = { 179, -179, 0, -61, -176, 228 }, | 520 | .cmatrix = { 179, -179, 0, -61, -176, 228 }, |
521 | .bpp = 2, | ||
522 | }, | ||
523 | { | ||
524 | .desc = "Raw RGB Bayer", | ||
525 | .pixelformat = V4L2_PIX_FMT_SBGGR8, | ||
526 | .regs = ov7670_fmt_raw, | ||
527 | .cmatrix = { 0, 0, 0, 0, 0, 0 }, | ||
528 | .bpp = 1 | ||
504 | }, | 529 | }, |
505 | }; | 530 | }; |
506 | #define N_OV7670_FMTS (sizeof(ov7670_formats)/sizeof(ov7670_formats[0])) | 531 | #define N_OV7670_FMTS ARRAY_SIZE(ov7670_formats) |
507 | 532 | ||
508 | /* | ||
509 | * All formats we support are 2 bytes/pixel. | ||
510 | */ | ||
511 | #define BYTES_PER_PIXEL 2 | ||
512 | 533 | ||
513 | /* | 534 | /* |
514 | * Then there is the issue of window sizes. Try to capture the info here. | 535 | * Then there is the issue of window sizes. Try to capture the info here. |
@@ -685,7 +706,7 @@ static int ov7670_try_fmt(struct i2c_client *c, struct v4l2_format *fmt, | |||
685 | */ | 706 | */ |
686 | pix->width = wsize->width; | 707 | pix->width = wsize->width; |
687 | pix->height = wsize->height; | 708 | pix->height = wsize->height; |
688 | pix->bytesperline = pix->width*BYTES_PER_PIXEL; | 709 | pix->bytesperline = pix->width*ov7670_formats[index].bpp; |
689 | pix->sizeimage = pix->height*pix->bytesperline; | 710 | pix->sizeimage = pix->height*pix->bytesperline; |
690 | return 0; | 711 | return 0; |
691 | } | 712 | } |
@@ -1270,9 +1291,8 @@ static int ov7670_command(struct i2c_client *client, unsigned int cmd, | |||
1270 | void *arg) | 1291 | void *arg) |
1271 | { | 1292 | { |
1272 | switch (cmd) { | 1293 | switch (cmd) { |
1273 | case VIDIOC_INT_G_CHIP_IDENT: | 1294 | case VIDIOC_G_CHIP_IDENT: |
1274 | * (enum v4l2_chip_ident *) arg = V4L2_IDENT_OV7670; | 1295 | return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_OV7670, 0); |
1275 | return 0; | ||
1276 | 1296 | ||
1277 | case VIDIOC_INT_RESET: | 1297 | case VIDIOC_INT_RESET: |
1278 | ov7670_reset(client); | 1298 | ov7670_reset(client); |
diff --git a/drivers/media/video/planb.c b/drivers/media/video/planb.c index e6e61df0d071..1455a8f4e930 100644 --- a/drivers/media/video/planb.c +++ b/drivers/media/video/planb.c | |||
@@ -2210,7 +2210,7 @@ static int find_planb(void) | |||
2210 | "membase 0x%x (base reg. 0x%x)\n", | 2210 | "membase 0x%x (base reg. 0x%x)\n", |
2211 | bus, PCI_SLOT(dev_fn), PCI_FUNC(dev_fn), old_base, confreg); | 2211 | bus, PCI_SLOT(dev_fn), PCI_FUNC(dev_fn), old_base, confreg); |
2212 | 2212 | ||
2213 | pdev = pci_find_slot (bus, dev_fn); | 2213 | pdev = pci_get_bus_and_slot(bus, dev_fn); |
2214 | if (!pdev) { | 2214 | if (!pdev) { |
2215 | printk(KERN_ERR "planb: cannot find slot\n"); | 2215 | printk(KERN_ERR "planb: cannot find slot\n"); |
2216 | goto err_out; | 2216 | goto err_out; |
@@ -2240,6 +2240,7 @@ static int find_planb(void) | |||
2240 | pb->planb_base = planb_regs; | 2240 | pb->planb_base = planb_regs; |
2241 | pb->planb_base_phys = (struct planb_registers *)new_base; | 2241 | pb->planb_base_phys = (struct planb_registers *)new_base; |
2242 | pb->irq = irq; | 2242 | pb->irq = irq; |
2243 | pb->dev = pdev; | ||
2243 | 2244 | ||
2244 | return planb_num; | 2245 | return planb_num; |
2245 | 2246 | ||
@@ -2247,6 +2248,7 @@ err_out_disable: | |||
2247 | pci_disable_device(pdev); | 2248 | pci_disable_device(pdev); |
2248 | err_out: | 2249 | err_out: |
2249 | /* FIXME handle error */ /* comment moved from pci_find_slot, above */ | 2250 | /* FIXME handle error */ /* comment moved from pci_find_slot, above */ |
2251 | pci_dev_put(pdev); | ||
2250 | return 0; | 2252 | return 0; |
2251 | } | 2253 | } |
2252 | 2254 | ||
@@ -2274,6 +2276,8 @@ static void release_planb(void) | |||
2274 | printk(KERN_INFO "PlanB: unregistering with v4l\n"); | 2276 | printk(KERN_INFO "PlanB: unregistering with v4l\n"); |
2275 | video_unregister_device(&pb->video_dev); | 2277 | video_unregister_device(&pb->video_dev); |
2276 | 2278 | ||
2279 | pci_dev_put(pb->dev); | ||
2280 | |||
2277 | /* note that iounmap() does nothing on the PPC right now */ | 2281 | /* note that iounmap() does nothing on the PPC right now */ |
2278 | iounmap ((void *)pb->planb_base); | 2282 | iounmap ((void *)pb->planb_base); |
2279 | } | 2283 | } |
diff --git a/drivers/media/video/planb.h b/drivers/media/video/planb.h index 92823211d0c5..e21b5735c103 100644 --- a/drivers/media/video/planb.h +++ b/drivers/media/video/planb.h | |||
@@ -177,6 +177,7 @@ struct planb { | |||
177 | struct mutex lock; | 177 | struct mutex lock; |
178 | unsigned int irq; /* interrupt number */ | 178 | unsigned int irq; /* interrupt number */ |
179 | volatile unsigned int intr_mask; | 179 | volatile unsigned int intr_mask; |
180 | struct pci_dev *dev; /* Our PCI device */ | ||
180 | 181 | ||
181 | int overlay; /* overlay running? */ | 182 | int overlay; /* overlay running? */ |
182 | struct planb_window win; | 183 | struct planb_window win; |
diff --git a/drivers/media/video/pvrusb2/pvrusb2-encoder.c b/drivers/media/video/pvrusb2/pvrusb2-encoder.c index 5786faf9b3b8..5669c8ca9ca3 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-encoder.c +++ b/drivers/media/video/pvrusb2/pvrusb2-encoder.c | |||
@@ -324,7 +324,7 @@ static int pvr2_encoder_vcmd(struct pvr2_hdw *hdw, int cmd, | |||
324 | 324 | ||
325 | /* This implements some extra setup for the encoder that seems to be | 325 | /* This implements some extra setup for the encoder that seems to be |
326 | specific to the PVR USB2 hardware. */ | 326 | specific to the PVR USB2 hardware. */ |
327 | int pvr2_encoder_prep_config(struct pvr2_hdw *hdw) | 327 | static int pvr2_encoder_prep_config(struct pvr2_hdw *hdw) |
328 | { | 328 | { |
329 | int ret = 0; | 329 | int ret = 0; |
330 | int encMisc3Arg = 0; | 330 | int encMisc3Arg = 0; |
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h index 16bd74199601..ce66ab8ff2d8 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h | |||
@@ -283,6 +283,8 @@ struct pvr2_hdw { | |||
283 | int unit_number; /* ID for driver instance */ | 283 | int unit_number; /* ID for driver instance */ |
284 | unsigned long serial_number; /* ID for hardware itself */ | 284 | unsigned long serial_number; /* ID for hardware itself */ |
285 | 285 | ||
286 | char bus_info[32]; /* Bus location info */ | ||
287 | |||
286 | /* Minor numbers used by v4l logic (yes, this is a hack, as there | 288 | /* Minor numbers used by v4l logic (yes, this is a hack, as there |
287 | should be no v4l junk here). Probably a better way to do this. */ | 289 | should be no v4l junk here). Probably a better way to do this. */ |
288 | int v4l_minor_number_video; | 290 | int v4l_minor_number_video; |
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index 9916cf32494d..acf651e01f94 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c | |||
@@ -1008,6 +1008,13 @@ unsigned long pvr2_hdw_get_sn(struct pvr2_hdw *hdw) | |||
1008 | return hdw->serial_number; | 1008 | return hdw->serial_number; |
1009 | } | 1009 | } |
1010 | 1010 | ||
1011 | |||
1012 | const char *pvr2_hdw_get_bus_info(struct pvr2_hdw *hdw) | ||
1013 | { | ||
1014 | return hdw->bus_info; | ||
1015 | } | ||
1016 | |||
1017 | |||
1011 | unsigned long pvr2_hdw_get_cur_freq(struct pvr2_hdw *hdw) | 1018 | unsigned long pvr2_hdw_get_cur_freq(struct pvr2_hdw *hdw) |
1012 | { | 1019 | { |
1013 | return hdw->freqSelector ? hdw->freqValTelevision : hdw->freqValRadio; | 1020 | return hdw->freqSelector ? hdw->freqValTelevision : hdw->freqValRadio; |
@@ -2105,6 +2112,11 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, | |||
2105 | hdw->usb_intf = intf; | 2112 | hdw->usb_intf = intf; |
2106 | hdw->usb_dev = interface_to_usbdev(intf); | 2113 | hdw->usb_dev = interface_to_usbdev(intf); |
2107 | 2114 | ||
2115 | scnprintf(hdw->bus_info,sizeof(hdw->bus_info), | ||
2116 | "usb %s address %d", | ||
2117 | hdw->usb_dev->dev.bus_id, | ||
2118 | hdw->usb_dev->devnum); | ||
2119 | |||
2108 | ifnum = hdw->usb_intf->cur_altsetting->desc.bInterfaceNumber; | 2120 | ifnum = hdw->usb_intf->cur_altsetting->desc.bInterfaceNumber; |
2109 | usb_set_interface(hdw->usb_dev,ifnum,0); | 2121 | usb_set_interface(hdw->usb_dev,ifnum,0); |
2110 | 2122 | ||
@@ -3275,7 +3287,9 @@ int pvr2_hdw_register_access(struct pvr2_hdw *hdw, | |||
3275 | mutex_lock(&hdw->i2c_list_lock); do { | 3287 | mutex_lock(&hdw->i2c_list_lock); do { |
3276 | list_for_each(item,&hdw->i2c_clients) { | 3288 | list_for_each(item,&hdw->i2c_clients) { |
3277 | cp = list_entry(item,struct pvr2_i2c_client,list); | 3289 | cp = list_entry(item,struct pvr2_i2c_client,list); |
3278 | if (!v4l2_chip_match_i2c_client(cp->client, req.match_type, req.match_chip)) { | 3290 | if (!v4l2_chip_match_i2c_client( |
3291 | cp->client, | ||
3292 | req.match_type, req.match_chip)) { | ||
3279 | continue; | 3293 | continue; |
3280 | } | 3294 | } |
3281 | stat = pvr2_i2c_client_cmd( | 3295 | stat = pvr2_i2c_client_cmd( |
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/drivers/media/video/pvrusb2/pvrusb2-hdw.h index 0c9cca43ff85..4dba8d006324 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.h +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.h | |||
@@ -124,6 +124,9 @@ struct usb_device *pvr2_hdw_get_dev(struct pvr2_hdw *); | |||
124 | /* Retrieve serial number of device */ | 124 | /* Retrieve serial number of device */ |
125 | unsigned long pvr2_hdw_get_sn(struct pvr2_hdw *); | 125 | unsigned long pvr2_hdw_get_sn(struct pvr2_hdw *); |
126 | 126 | ||
127 | /* Retrieve bus location info of device */ | ||
128 | const char *pvr2_hdw_get_bus_info(struct pvr2_hdw *); | ||
129 | |||
127 | /* Called when hardware has been unplugged */ | 130 | /* Called when hardware has been unplugged */ |
128 | void pvr2_hdw_disconnect(struct pvr2_hdw *); | 131 | void pvr2_hdw_disconnect(struct pvr2_hdw *); |
129 | 132 | ||
diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c index 91396fd573e4..a741c556a39a 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c +++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c | |||
@@ -42,9 +42,11 @@ struct pvr2_sysfs { | |||
42 | struct class_device_attribute attr_v4l_minor_number; | 42 | struct class_device_attribute attr_v4l_minor_number; |
43 | struct class_device_attribute attr_v4l_radio_minor_number; | 43 | struct class_device_attribute attr_v4l_radio_minor_number; |
44 | struct class_device_attribute attr_unit_number; | 44 | struct class_device_attribute attr_unit_number; |
45 | struct class_device_attribute attr_bus_info; | ||
45 | int v4l_minor_number_created_ok; | 46 | int v4l_minor_number_created_ok; |
46 | int v4l_radio_minor_number_created_ok; | 47 | int v4l_radio_minor_number_created_ok; |
47 | int unit_number_created_ok; | 48 | int unit_number_created_ok; |
49 | int bus_info_created_ok; | ||
48 | }; | 50 | }; |
49 | 51 | ||
50 | #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC | 52 | #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC |
@@ -705,6 +707,10 @@ static void class_dev_destroy(struct pvr2_sysfs *sfp) | |||
705 | pvr2_sysfs_tear_down_debugifc(sfp); | 707 | pvr2_sysfs_tear_down_debugifc(sfp); |
706 | #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ | 708 | #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ |
707 | pvr2_sysfs_tear_down_controls(sfp); | 709 | pvr2_sysfs_tear_down_controls(sfp); |
710 | if (sfp->bus_info_created_ok) { | ||
711 | class_device_remove_file(sfp->class_dev, | ||
712 | &sfp->attr_bus_info); | ||
713 | } | ||
708 | if (sfp->v4l_minor_number_created_ok) { | 714 | if (sfp->v4l_minor_number_created_ok) { |
709 | class_device_remove_file(sfp->class_dev, | 715 | class_device_remove_file(sfp->class_dev, |
710 | &sfp->attr_v4l_minor_number); | 716 | &sfp->attr_v4l_minor_number); |
@@ -735,6 +741,16 @@ static ssize_t v4l_minor_number_show(struct class_device *class_dev,char *buf) | |||
735 | } | 741 | } |
736 | 742 | ||
737 | 743 | ||
744 | static ssize_t bus_info_show(struct class_device *class_dev,char *buf) | ||
745 | { | ||
746 | struct pvr2_sysfs *sfp; | ||
747 | sfp = (struct pvr2_sysfs *)class_dev->class_data; | ||
748 | if (!sfp) return -EINVAL; | ||
749 | return scnprintf(buf,PAGE_SIZE,"%s\n", | ||
750 | pvr2_hdw_get_bus_info(sfp->channel.hdw)); | ||
751 | } | ||
752 | |||
753 | |||
738 | static ssize_t v4l_radio_minor_number_show(struct class_device *class_dev, | 754 | static ssize_t v4l_radio_minor_number_show(struct class_device *class_dev, |
739 | char *buf) | 755 | char *buf) |
740 | { | 756 | { |
@@ -836,6 +852,20 @@ static void class_dev_create(struct pvr2_sysfs *sfp, | |||
836 | sfp->unit_number_created_ok = !0; | 852 | sfp->unit_number_created_ok = !0; |
837 | } | 853 | } |
838 | 854 | ||
855 | sfp->attr_bus_info.attr.owner = THIS_MODULE; | ||
856 | sfp->attr_bus_info.attr.name = "bus_info_str"; | ||
857 | sfp->attr_bus_info.attr.mode = S_IRUGO; | ||
858 | sfp->attr_bus_info.show = bus_info_show; | ||
859 | sfp->attr_bus_info.store = NULL; | ||
860 | ret = class_device_create_file(sfp->class_dev, | ||
861 | &sfp->attr_bus_info); | ||
862 | if (ret < 0) { | ||
863 | printk(KERN_WARNING "%s: class_device_create_file error: %d\n", | ||
864 | __FUNCTION__, ret); | ||
865 | } else { | ||
866 | sfp->bus_info_created_ok = !0; | ||
867 | } | ||
868 | |||
839 | pvr2_sysfs_add_controls(sfp); | 869 | pvr2_sysfs_add_controls(sfp); |
840 | #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC | 870 | #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC |
841 | pvr2_sysfs_add_debugifc(sfp); | 871 | pvr2_sysfs_add_debugifc(sfp); |
diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c index 25d3830b482a..4563b3df8a0d 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c | |||
@@ -203,6 +203,8 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file, | |||
203 | struct v4l2_capability *cap = arg; | 203 | struct v4l2_capability *cap = arg; |
204 | 204 | ||
205 | memcpy(cap, &pvr_capability, sizeof(struct v4l2_capability)); | 205 | memcpy(cap, &pvr_capability, sizeof(struct v4l2_capability)); |
206 | strlcpy(cap->bus_info,pvr2_hdw_get_bus_info(hdw), | ||
207 | sizeof(cap->bus_info)); | ||
206 | 208 | ||
207 | ret = 0; | 209 | ret = 0; |
208 | break; | 210 | break; |
diff --git a/drivers/media/video/pwc/pwc-ctrl.c b/drivers/media/video/pwc/pwc-ctrl.c index 0bd115588f31..338ced7188f2 100644 --- a/drivers/media/video/pwc/pwc-ctrl.c +++ b/drivers/media/video/pwc/pwc-ctrl.c | |||
@@ -140,6 +140,8 @@ static const char *size2name[PSZ_MAX] = | |||
140 | An alternate value of 0 means this mode is not available at all. | 140 | An alternate value of 0 means this mode is not available at all. |
141 | */ | 141 | */ |
142 | 142 | ||
143 | #define PWC_FPS_MAX_NALA 8 | ||
144 | |||
143 | struct Nala_table_entry { | 145 | struct Nala_table_entry { |
144 | char alternate; /* USB alternate setting */ | 146 | char alternate; /* USB alternate setting */ |
145 | int compressed; /* Compressed yes/no */ | 147 | int compressed; /* Compressed yes/no */ |
@@ -147,7 +149,9 @@ struct Nala_table_entry { | |||
147 | unsigned char mode[3]; /* precomputed mode table */ | 149 | unsigned char mode[3]; /* precomputed mode table */ |
148 | }; | 150 | }; |
149 | 151 | ||
150 | static struct Nala_table_entry Nala_table[PSZ_MAX][8] = | 152 | static unsigned int Nala_fps_vector[PWC_FPS_MAX_NALA] = { 4, 5, 7, 10, 12, 15, 20, 24 }; |
153 | |||
154 | static struct Nala_table_entry Nala_table[PSZ_MAX][PWC_FPS_MAX_NALA] = | ||
151 | { | 155 | { |
152 | #include "pwc-nala.h" | 156 | #include "pwc-nala.h" |
153 | }; | 157 | }; |
@@ -423,6 +427,59 @@ int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frame | |||
423 | return 0; | 427 | return 0; |
424 | } | 428 | } |
425 | 429 | ||
430 | static unsigned int pwc_get_fps_Nala(struct pwc_device *pdev, unsigned int index, unsigned int size) | ||
431 | { | ||
432 | unsigned int i; | ||
433 | |||
434 | for (i = 0; i < PWC_FPS_MAX_NALA; i++) { | ||
435 | if (Nala_table[size][i].alternate) { | ||
436 | if (index--==0) return Nala_fps_vector[i]; | ||
437 | } | ||
438 | } | ||
439 | return 0; | ||
440 | } | ||
441 | |||
442 | static unsigned int pwc_get_fps_Kiara(struct pwc_device *pdev, unsigned int index, unsigned int size) | ||
443 | { | ||
444 | unsigned int i; | ||
445 | |||
446 | for (i = 0; i < PWC_FPS_MAX_KIARA; i++) { | ||
447 | if (Kiara_table[size][i][3].alternate) { | ||
448 | if (index--==0) return Kiara_fps_vector[i]; | ||
449 | } | ||
450 | } | ||
451 | return 0; | ||
452 | } | ||
453 | |||
454 | static unsigned int pwc_get_fps_Timon(struct pwc_device *pdev, unsigned int index, unsigned int size) | ||
455 | { | ||
456 | unsigned int i; | ||
457 | |||
458 | for (i=0; i < PWC_FPS_MAX_TIMON; i++) { | ||
459 | if (Timon_table[size][i][3].alternate) { | ||
460 | if (index--==0) return Timon_fps_vector[i]; | ||
461 | } | ||
462 | } | ||
463 | return 0; | ||
464 | } | ||
465 | |||
466 | unsigned int pwc_get_fps(struct pwc_device *pdev, unsigned int index, unsigned int size) | ||
467 | { | ||
468 | unsigned int ret; | ||
469 | |||
470 | if (DEVICE_USE_CODEC1(pdev->type)) { | ||
471 | ret = pwc_get_fps_Nala(pdev, index, size); | ||
472 | |||
473 | } else if (DEVICE_USE_CODEC3(pdev->type)) { | ||
474 | ret = pwc_get_fps_Kiara(pdev, index, size); | ||
475 | |||
476 | } else { | ||
477 | ret = pwc_get_fps_Timon(pdev, index, size); | ||
478 | } | ||
479 | |||
480 | return ret; | ||
481 | } | ||
482 | |||
426 | #define BLACK_Y 0 | 483 | #define BLACK_Y 0 |
427 | #define BLACK_U 128 | 484 | #define BLACK_U 128 |
428 | #define BLACK_V 128 | 485 | #define BLACK_V 128 |
@@ -1343,7 +1400,7 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg) | |||
1343 | ret = pwc_read_red_gain(pdev, &ARGR(wb).read_red); | 1400 | ret = pwc_read_red_gain(pdev, &ARGR(wb).read_red); |
1344 | if (ret < 0) | 1401 | if (ret < 0) |
1345 | break; | 1402 | break; |
1346 | ret =pwc_read_blue_gain(pdev, &ARGR(wb).read_blue); | 1403 | ret = pwc_read_blue_gain(pdev, &ARGR(wb).read_blue); |
1347 | if (ret < 0) | 1404 | if (ret < 0) |
1348 | break; | 1405 | break; |
1349 | } | 1406 | } |
diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index 27ed76986ca2..085332a503de 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c | |||
@@ -95,8 +95,8 @@ static const struct usb_device_id pwc_device_table [] = { | |||
95 | { USB_DEVICE(0x046D, 0x08B3) }, /* Logitech QuickCam Zoom (old model) */ | 95 | { USB_DEVICE(0x046D, 0x08B3) }, /* Logitech QuickCam Zoom (old model) */ |
96 | { USB_DEVICE(0x046D, 0x08B4) }, /* Logitech QuickCam Zoom (new model) */ | 96 | { USB_DEVICE(0x046D, 0x08B4) }, /* Logitech QuickCam Zoom (new model) */ |
97 | { USB_DEVICE(0x046D, 0x08B5) }, /* Logitech QuickCam Orbit/Sphere */ | 97 | { USB_DEVICE(0x046D, 0x08B5) }, /* Logitech QuickCam Orbit/Sphere */ |
98 | { USB_DEVICE(0x046D, 0x08B6) }, /* Logitech (reserved) */ | 98 | { USB_DEVICE(0x046D, 0x08B6) }, /* Cisco VT Camera */ |
99 | { USB_DEVICE(0x046D, 0x08B7) }, /* Logitech (reserved) */ | 99 | { USB_DEVICE(0x046D, 0x08B7) }, /* Logitech ViewPort AV 100 */ |
100 | { USB_DEVICE(0x046D, 0x08B8) }, /* Logitech (reserved) */ | 100 | { USB_DEVICE(0x046D, 0x08B8) }, /* Logitech (reserved) */ |
101 | { USB_DEVICE(0x055D, 0x9000) }, /* Samsung MPC-C10 */ | 101 | { USB_DEVICE(0x055D, 0x9000) }, /* Samsung MPC-C10 */ |
102 | { USB_DEVICE(0x055D, 0x9001) }, /* Samsung MPC-C30 */ | 102 | { USB_DEVICE(0x055D, 0x9001) }, /* Samsung MPC-C30 */ |
@@ -1493,7 +1493,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id | |||
1493 | case 0x0329: | 1493 | case 0x0329: |
1494 | PWC_INFO("Philips SPC 900NC USB webcam detected.\n"); | 1494 | PWC_INFO("Philips SPC 900NC USB webcam detected.\n"); |
1495 | name = "Philips SPC 900NC webcam"; | 1495 | name = "Philips SPC 900NC webcam"; |
1496 | type_id = 720; | 1496 | type_id = 740; |
1497 | break; | 1497 | break; |
1498 | default: | 1498 | default: |
1499 | return -ENODEV; | 1499 | return -ENODEV; |
@@ -1547,8 +1547,16 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id | |||
1547 | features |= FEATURE_MOTOR_PANTILT; | 1547 | features |= FEATURE_MOTOR_PANTILT; |
1548 | break; | 1548 | break; |
1549 | case 0x08b6: | 1549 | case 0x08b6: |
1550 | PWC_INFO("Logitech/Cisco VT Camera webcam detected.\n"); | ||
1551 | name = "Cisco VT Camera"; | ||
1552 | type_id = 740; /* CCD sensor */ | ||
1553 | break; | ||
1550 | case 0x08b7: | 1554 | case 0x08b7: |
1551 | case 0x08b8: | 1555 | PWC_INFO("Logitech ViewPort AV 100 webcam detected.\n"); |
1556 | name = "Logitech ViewPort AV 100"; | ||
1557 | type_id = 740; /* CCD sensor */ | ||
1558 | break; | ||
1559 | case 0x08b8: /* Where this released? */ | ||
1552 | PWC_INFO("Logitech QuickCam detected (reserved ID).\n"); | 1560 | PWC_INFO("Logitech QuickCam detected (reserved ID).\n"); |
1553 | name = "Logitech QuickCam (res.)"; | 1561 | name = "Logitech QuickCam (res.)"; |
1554 | type_id = 730; /* Assuming CMOS */ | 1562 | type_id = 730; /* Assuming CMOS */ |
diff --git a/drivers/media/video/pwc/pwc-ioctl.h b/drivers/media/video/pwc/pwc-ioctl.h index 784bc72521fa..cec660299768 100644 --- a/drivers/media/video/pwc/pwc-ioctl.h +++ b/drivers/media/video/pwc/pwc-ioctl.h | |||
@@ -2,7 +2,7 @@ | |||
2 | #define PWC_IOCTL_H | 2 | #define PWC_IOCTL_H |
3 | 3 | ||
4 | /* (C) 2001-2004 Nemosoft Unv. | 4 | /* (C) 2001-2004 Nemosoft Unv. |
5 | (C) 2004 Luc Saillard (luc@saillard.org) | 5 | (C) 2004-2006 Luc Saillard (luc@saillard.org) |
6 | 6 | ||
7 | NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx | 7 | NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx |
8 | driver and thus may have bugs that are not present in the original version. | 8 | driver and thus may have bugs that are not present in the original version. |
@@ -25,7 +25,7 @@ | |||
25 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 25 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
26 | */ | 26 | */ |
27 | 27 | ||
28 | /* This is pwc-ioctl.h belonging to PWC 8.12.1 | 28 | /* This is pwc-ioctl.h belonging to PWC 10.0.10 |
29 | It contains structures and defines to communicate from user space | 29 | It contains structures and defines to communicate from user space |
30 | directly to the driver. | 30 | directly to the driver. |
31 | */ | 31 | */ |
@@ -51,6 +51,9 @@ | |||
51 | ... the function | 51 | ... the function |
52 | */ | 52 | */ |
53 | 53 | ||
54 | #include <linux/types.h> | ||
55 | #include <linux/version.h> | ||
56 | |||
54 | 57 | ||
55 | /* Enumeration of image sizes */ | 58 | /* Enumeration of image sizes */ |
56 | #define PSZ_SQCIF 0x00 | 59 | #define PSZ_SQCIF 0x00 |
@@ -65,6 +68,8 @@ | |||
65 | /* The frame rate is encoded in the video_window.flags parameter using | 68 | /* The frame rate is encoded in the video_window.flags parameter using |
66 | the upper 16 bits, since some flags are defined nowadays. The following | 69 | the upper 16 bits, since some flags are defined nowadays. The following |
67 | defines provide a mask and shift to filter out this value. | 70 | defines provide a mask and shift to filter out this value. |
71 | This value can also be passing using the private flag when using v4l2 and | ||
72 | VIDIOC_S_FMT ioctl. | ||
68 | 73 | ||
69 | In 'Snapshot' mode the camera freezes its automatic exposure and colour | 74 | In 'Snapshot' mode the camera freezes its automatic exposure and colour |
70 | balance controls. | 75 | balance controls. |
@@ -73,6 +78,8 @@ | |||
73 | #define PWC_FPS_MASK 0x00FF0000 | 78 | #define PWC_FPS_MASK 0x00FF0000 |
74 | #define PWC_FPS_FRMASK 0x003F0000 | 79 | #define PWC_FPS_FRMASK 0x003F0000 |
75 | #define PWC_FPS_SNAPSHOT 0x00400000 | 80 | #define PWC_FPS_SNAPSHOT 0x00400000 |
81 | #define PWC_QLT_MASK 0x03000000 | ||
82 | #define PWC_QLT_SHIFT 24 | ||
76 | 83 | ||
77 | 84 | ||
78 | /* structure for transferring x & y coordinates */ | 85 | /* structure for transferring x & y coordinates */ |
@@ -289,4 +296,29 @@ struct pwc_table_init_buffer { | |||
289 | }; | 296 | }; |
290 | #define VIDIOCPWCGVIDTABLE _IOR('v', 216, struct pwc_table_init_buffer) | 297 | #define VIDIOCPWCGVIDTABLE _IOR('v', 216, struct pwc_table_init_buffer) |
291 | 298 | ||
299 | /* | ||
300 | * This is private command used when communicating with v4l2. | ||
301 | * In the future all private ioctl will be remove/replace to | ||
302 | * use interface offer by v4l2. | ||
303 | */ | ||
304 | |||
305 | #define V4L2_CID_PRIVATE_SAVE_USER (V4L2_CID_PRIVATE_BASE + 0) | ||
306 | #define V4L2_CID_PRIVATE_RESTORE_USER (V4L2_CID_PRIVATE_BASE + 1) | ||
307 | #define V4L2_CID_PRIVATE_RESTORE_FACTORY (V4L2_CID_PRIVATE_BASE + 2) | ||
308 | #define V4L2_CID_PRIVATE_COLOUR_MODE (V4L2_CID_PRIVATE_BASE + 3) | ||
309 | #define V4L2_CID_PRIVATE_AUTOCONTOUR (V4L2_CID_PRIVATE_BASE + 4) | ||
310 | #define V4L2_CID_PRIVATE_CONTOUR (V4L2_CID_PRIVATE_BASE + 5) | ||
311 | #define V4L2_CID_PRIVATE_BACKLIGHT (V4L2_CID_PRIVATE_BASE + 6) | ||
312 | #define V4L2_CID_PRIVATE_FLICKERLESS (V4L2_CID_PRIVATE_BASE + 7) | ||
313 | #define V4L2_CID_PRIVATE_NOISE_REDUCTION (V4L2_CID_PRIVATE_BASE + 8) | ||
314 | |||
315 | struct pwc_raw_frame { | ||
316 | __le16 type; /* type of the webcam */ | ||
317 | __le16 vbandlength; /* Size of 4lines compressed (used by the decompressor) */ | ||
318 | __u8 cmd[4]; /* the four byte of the command (in case of nala, | ||
319 | only the first 3 bytes is filled) */ | ||
320 | __u8 rawframe[0]; /* frame_size = H/4*vbandlength */ | ||
321 | } __attribute__ ((packed)); | ||
322 | |||
323 | |||
292 | #endif | 324 | #endif |
diff --git a/drivers/media/video/pwc/pwc-kiara.c b/drivers/media/video/pwc/pwc-kiara.c index fec39cc5a9f1..f4ae83c0cf2b 100644 --- a/drivers/media/video/pwc/pwc-kiara.c +++ b/drivers/media/video/pwc/pwc-kiara.c | |||
@@ -42,6 +42,8 @@ | |||
42 | #include "pwc-kiara.h" | 42 | #include "pwc-kiara.h" |
43 | #include "pwc-uncompress.h" | 43 | #include "pwc-uncompress.h" |
44 | 44 | ||
45 | const unsigned int Kiara_fps_vector[PWC_FPS_MAX_KIARA] = { 5, 10, 15, 20, 25, 30 }; | ||
46 | |||
45 | const struct Kiara_table_entry Kiara_table[PSZ_MAX][6][4] = | 47 | const struct Kiara_table_entry Kiara_table[PSZ_MAX][6][4] = |
46 | { | 48 | { |
47 | /* SQCIF */ | 49 | /* SQCIF */ |
diff --git a/drivers/media/video/pwc/pwc-kiara.h b/drivers/media/video/pwc/pwc-kiara.h index 0bdb22547d86..047dad8c15f7 100644 --- a/drivers/media/video/pwc/pwc-kiara.h +++ b/drivers/media/video/pwc/pwc-kiara.h | |||
@@ -29,6 +29,8 @@ | |||
29 | 29 | ||
30 | #include <media/pwc-ioctl.h> | 30 | #include <media/pwc-ioctl.h> |
31 | 31 | ||
32 | #define PWC_FPS_MAX_KIARA 6 | ||
33 | |||
32 | struct Kiara_table_entry | 34 | struct Kiara_table_entry |
33 | { | 35 | { |
34 | char alternate; /* USB alternate interface */ | 36 | char alternate; /* USB alternate interface */ |
@@ -37,8 +39,9 @@ struct Kiara_table_entry | |||
37 | unsigned char mode[12]; /* precomputed mode settings for cam */ | 39 | unsigned char mode[12]; /* precomputed mode settings for cam */ |
38 | }; | 40 | }; |
39 | 41 | ||
40 | extern const struct Kiara_table_entry Kiara_table[PSZ_MAX][6][4]; | 42 | extern const struct Kiara_table_entry Kiara_table[PSZ_MAX][PWC_FPS_MAX_KIARA][4]; |
41 | extern const unsigned int KiaraRomTable[8][2][16][8]; | 43 | extern const unsigned int KiaraRomTable[8][2][16][8]; |
44 | extern const unsigned int Kiara_fps_vector[PWC_FPS_MAX_KIARA]; | ||
42 | 45 | ||
43 | #endif | 46 | #endif |
44 | 47 | ||
diff --git a/drivers/media/video/pwc/pwc-timon.c b/drivers/media/video/pwc/pwc-timon.c index be65bdcd195b..c56c174b161c 100644 --- a/drivers/media/video/pwc/pwc-timon.c +++ b/drivers/media/video/pwc/pwc-timon.c | |||
@@ -40,7 +40,9 @@ | |||
40 | 40 | ||
41 | #include "pwc-timon.h" | 41 | #include "pwc-timon.h" |
42 | 42 | ||
43 | const struct Timon_table_entry Timon_table[PSZ_MAX][6][4] = | 43 | const unsigned int Timon_fps_vector[PWC_FPS_MAX_TIMON] = { 5, 10, 15, 20, 25, 30 }; |
44 | |||
45 | const struct Timon_table_entry Timon_table[PSZ_MAX][PWC_FPS_MAX_TIMON][4] = | ||
44 | { | 46 | { |
45 | /* SQCIF */ | 47 | /* SQCIF */ |
46 | { | 48 | { |
diff --git a/drivers/media/video/pwc/pwc-timon.h b/drivers/media/video/pwc/pwc-timon.h index eef9e2cd4320..a6e22224c95f 100644 --- a/drivers/media/video/pwc/pwc-timon.h +++ b/drivers/media/video/pwc/pwc-timon.h | |||
@@ -44,6 +44,8 @@ | |||
44 | 44 | ||
45 | #include <media/pwc-ioctl.h> | 45 | #include <media/pwc-ioctl.h> |
46 | 46 | ||
47 | #define PWC_FPS_MAX_TIMON 6 | ||
48 | |||
47 | struct Timon_table_entry | 49 | struct Timon_table_entry |
48 | { | 50 | { |
49 | char alternate; /* USB alternate interface */ | 51 | char alternate; /* USB alternate interface */ |
@@ -52,9 +54,9 @@ struct Timon_table_entry | |||
52 | unsigned char mode[13]; /* precomputed mode settings for cam */ | 54 | unsigned char mode[13]; /* precomputed mode settings for cam */ |
53 | }; | 55 | }; |
54 | 56 | ||
55 | extern const struct Timon_table_entry Timon_table[PSZ_MAX][6][4]; | 57 | extern const struct Timon_table_entry Timon_table[PSZ_MAX][PWC_FPS_MAX_TIMON][4]; |
56 | extern const unsigned int TimonRomTable [16][2][16][8]; | 58 | extern const unsigned int TimonRomTable [16][2][16][8]; |
57 | 59 | extern const unsigned int Timon_fps_vector[PWC_FPS_MAX_TIMON]; | |
58 | 60 | ||
59 | #endif | 61 | #endif |
60 | 62 | ||
diff --git a/drivers/media/video/pwc/pwc-v4l.c b/drivers/media/video/pwc/pwc-v4l.c index d5e6bc850643..32fbe1ae6251 100644 --- a/drivers/media/video/pwc/pwc-v4l.c +++ b/drivers/media/video/pwc/pwc-v4l.c | |||
@@ -1168,7 +1168,7 @@ int pwc_video_do_ioctl(struct inode *inode, struct file *file, | |||
1168 | buf->sequence = 0; | 1168 | buf->sequence = 0; |
1169 | buf->memory = V4L2_MEMORY_MMAP; | 1169 | buf->memory = V4L2_MEMORY_MMAP; |
1170 | buf->m.offset = pdev->fill_image * pdev->len_per_image; | 1170 | buf->m.offset = pdev->fill_image * pdev->len_per_image; |
1171 | buf->length = buf->bytesused; | 1171 | buf->length = pdev->len_per_image; |
1172 | pwc_next_image(pdev); | 1172 | pwc_next_image(pdev); |
1173 | 1173 | ||
1174 | PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->index=%d\n",buf->index); | 1174 | PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->index=%d\n",buf->index); |
@@ -1193,6 +1193,64 @@ int pwc_video_do_ioctl(struct inode *inode, struct file *file, | |||
1193 | return 0; | 1193 | return 0; |
1194 | } | 1194 | } |
1195 | 1195 | ||
1196 | case VIDIOC_ENUM_FRAMESIZES: | ||
1197 | { | ||
1198 | struct v4l2_frmsizeenum *fsize = arg; | ||
1199 | unsigned int i = 0, index = fsize->index; | ||
1200 | |||
1201 | if (fsize->pixel_format == V4L2_PIX_FMT_YUV420) { | ||
1202 | for (i = 0; i < PSZ_MAX; i++) { | ||
1203 | if (pdev->image_mask & (1UL << i)) { | ||
1204 | if (!index--) { | ||
1205 | fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; | ||
1206 | fsize->discrete.width = pwc_image_sizes[i].x; | ||
1207 | fsize->discrete.height = pwc_image_sizes[i].y; | ||
1208 | return 0; | ||
1209 | } | ||
1210 | } | ||
1211 | } | ||
1212 | } else if (fsize->index == 0 && | ||
1213 | ((fsize->pixel_format == V4L2_PIX_FMT_PWC1 && DEVICE_USE_CODEC1(pdev->type)) || | ||
1214 | (fsize->pixel_format == V4L2_PIX_FMT_PWC2 && DEVICE_USE_CODEC23(pdev->type)))) { | ||
1215 | |||
1216 | fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; | ||
1217 | fsize->discrete.width = pdev->abs_max.x; | ||
1218 | fsize->discrete.height = pdev->abs_max.y; | ||
1219 | return 0; | ||
1220 | } | ||
1221 | return -EINVAL; | ||
1222 | } | ||
1223 | |||
1224 | case VIDIOC_ENUM_FRAMEINTERVALS: | ||
1225 | { | ||
1226 | struct v4l2_frmivalenum *fival = arg; | ||
1227 | int size = -1; | ||
1228 | unsigned int i; | ||
1229 | |||
1230 | for (i = 0; i < PSZ_MAX; i++) { | ||
1231 | if (pwc_image_sizes[i].x == fival->width && | ||
1232 | pwc_image_sizes[i].y == fival->height) { | ||
1233 | size = i; | ||
1234 | break; | ||
1235 | } | ||
1236 | } | ||
1237 | |||
1238 | /* TODO: Support raw format */ | ||
1239 | if (size < 0 || fival->pixel_format != V4L2_PIX_FMT_YUV420) { | ||
1240 | return -EINVAL; | ||
1241 | } | ||
1242 | |||
1243 | i = pwc_get_fps(pdev, fival->index, size); | ||
1244 | if (!i) | ||
1245 | return -EINVAL; | ||
1246 | |||
1247 | fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; | ||
1248 | fival->discrete.numerator = 1; | ||
1249 | fival->discrete.denominator = i; | ||
1250 | |||
1251 | return 0; | ||
1252 | } | ||
1253 | |||
1196 | default: | 1254 | default: |
1197 | return pwc_ioctl(pdev, cmd, arg); | 1255 | return pwc_ioctl(pdev, cmd, arg); |
1198 | } /* ..switch */ | 1256 | } /* ..switch */ |
diff --git a/drivers/media/video/pwc/pwc.h b/drivers/media/video/pwc/pwc.h index e778a2b8c280..acbb9312960a 100644 --- a/drivers/media/video/pwc/pwc.h +++ b/drivers/media/video/pwc/pwc.h | |||
@@ -44,7 +44,7 @@ | |||
44 | #define PWC_MINOR 0 | 44 | #define PWC_MINOR 0 |
45 | #define PWC_EXTRAMINOR 12 | 45 | #define PWC_EXTRAMINOR 12 |
46 | #define PWC_VERSION_CODE KERNEL_VERSION(PWC_MAJOR,PWC_MINOR,PWC_EXTRAMINOR) | 46 | #define PWC_VERSION_CODE KERNEL_VERSION(PWC_MAJOR,PWC_MINOR,PWC_EXTRAMINOR) |
47 | #define PWC_VERSION "10.0.12" | 47 | #define PWC_VERSION "10.0.13" |
48 | #define PWC_NAME "pwc" | 48 | #define PWC_NAME "pwc" |
49 | #define PFX PWC_NAME ": " | 49 | #define PFX PWC_NAME ": " |
50 | 50 | ||
@@ -85,7 +85,7 @@ | |||
85 | #define PWC_INFO(fmt, args...) printk(KERN_INFO PFX fmt, ##args) | 85 | #define PWC_INFO(fmt, args...) printk(KERN_INFO PFX fmt, ##args) |
86 | #define PWC_TRACE(fmt, args...) PWC_DEBUG(TRACE, fmt, ##args) | 86 | #define PWC_TRACE(fmt, args...) PWC_DEBUG(TRACE, fmt, ##args) |
87 | 87 | ||
88 | #else /* if ! CONFIG_PWC_DEBUG */ | 88 | #else /* if ! CONFIG_USB_PWC_DEBUG */ |
89 | 89 | ||
90 | #define PWC_ERROR(fmt, args...) printk(KERN_ERR PFX fmt, ##args) | 90 | #define PWC_ERROR(fmt, args...) printk(KERN_ERR PFX fmt, ##args) |
91 | #define PWC_WARNING(fmt, args...) printk(KERN_WARNING PFX fmt, ##args) | 91 | #define PWC_WARNING(fmt, args...) printk(KERN_WARNING PFX fmt, ##args) |
@@ -287,6 +287,7 @@ void pwc_construct(struct pwc_device *pdev); | |||
287 | /** Functions in pwc-ctrl.c */ | 287 | /** Functions in pwc-ctrl.c */ |
288 | /* Request a certain video mode. Returns < 0 if not possible */ | 288 | /* Request a certain video mode. Returns < 0 if not possible */ |
289 | extern int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot); | 289 | extern int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot); |
290 | extern unsigned int pwc_get_fps(struct pwc_device *pdev, unsigned int index, unsigned int size); | ||
290 | /* Calculate the number of bytes per image (not frame) */ | 291 | /* Calculate the number of bytes per image (not frame) */ |
291 | extern int pwc_mpt_reset(struct pwc_device *pdev, int flags); | 292 | extern int pwc_mpt_reset(struct pwc_device *pdev, int flags); |
292 | extern int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt); | 293 | extern int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt); |
diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c index 4d5bbd859de1..2d18f0069821 100644 --- a/drivers/media/video/saa7115.c +++ b/drivers/media/video/saa7115.c | |||
@@ -45,6 +45,7 @@ | |||
45 | #include <linux/i2c.h> | 45 | #include <linux/i2c.h> |
46 | #include <linux/videodev2.h> | 46 | #include <linux/videodev2.h> |
47 | #include <media/v4l2-common.h> | 47 | #include <media/v4l2-common.h> |
48 | #include <media/v4l2-chip-ident.h> | ||
48 | #include <media/saa7115.h> | 49 | #include <media/saa7115.h> |
49 | #include <asm/div64.h> | 50 | #include <asm/div64.h> |
50 | 51 | ||
@@ -80,7 +81,7 @@ struct saa711x_state { | |||
80 | int sat; | 81 | int sat; |
81 | int width; | 82 | int width; |
82 | int height; | 83 | int height; |
83 | enum v4l2_chip_ident ident; | 84 | u32 ident; |
84 | u32 audclk_freq; | 85 | u32 audclk_freq; |
85 | u32 crystal_freq; | 86 | u32 crystal_freq; |
86 | u8 ucgc; | 87 | u8 ucgc; |
@@ -1232,7 +1233,6 @@ static void saa711x_decode_vbi_line(struct i2c_client *client, | |||
1232 | static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *arg) | 1233 | static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *arg) |
1233 | { | 1234 | { |
1234 | struct saa711x_state *state = i2c_get_clientdata(client); | 1235 | struct saa711x_state *state = i2c_get_clientdata(client); |
1235 | int *iarg = arg; | ||
1236 | 1236 | ||
1237 | /* ioctls to allow direct access to the saa7115 registers for testing */ | 1237 | /* ioctls to allow direct access to the saa7115 registers for testing */ |
1238 | switch (cmd) { | 1238 | switch (cmd) { |
@@ -1437,9 +1437,8 @@ static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *ar | |||
1437 | } | 1437 | } |
1438 | #endif | 1438 | #endif |
1439 | 1439 | ||
1440 | case VIDIOC_INT_G_CHIP_IDENT: | 1440 | case VIDIOC_G_CHIP_IDENT: |
1441 | *iarg = state->ident; | 1441 | return v4l2_chip_ident_i2c_client(client, arg, state->ident, 0); |
1442 | break; | ||
1443 | 1442 | ||
1444 | default: | 1443 | default: |
1445 | return -EINVAL; | 1444 | return -EINVAL; |
@@ -1487,6 +1486,7 @@ static int saa711x_attach(struct i2c_adapter *adapter, int address, int kind) | |||
1487 | if (memcmp(name, "1f711", 5)) { | 1486 | if (memcmp(name, "1f711", 5)) { |
1488 | v4l_dbg(1, debug, client, "chip found @ 0x%x (ID %s) does not match a known saa711x chip.\n", | 1487 | v4l_dbg(1, debug, client, "chip found @ 0x%x (ID %s) does not match a known saa711x chip.\n", |
1489 | address << 1, name); | 1488 | address << 1, name); |
1489 | kfree(client); | ||
1490 | return 0; | 1490 | return 0; |
1491 | } | 1491 | } |
1492 | 1492 | ||
diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c index 654863db1591..9f986930490f 100644 --- a/drivers/media/video/saa7127.c +++ b/drivers/media/video/saa7127.c | |||
@@ -54,6 +54,7 @@ | |||
54 | #include <linux/i2c.h> | 54 | #include <linux/i2c.h> |
55 | #include <linux/videodev2.h> | 55 | #include <linux/videodev2.h> |
56 | #include <media/v4l2-common.h> | 56 | #include <media/v4l2-common.h> |
57 | #include <media/v4l2-chip-ident.h> | ||
57 | #include <media/saa7127.h> | 58 | #include <media/saa7127.h> |
58 | 59 | ||
59 | static int debug = 0; | 60 | static int debug = 0; |
@@ -234,7 +235,7 @@ static struct i2c_reg_value saa7127_init_config_50hz[] = { | |||
234 | 235 | ||
235 | struct saa7127_state { | 236 | struct saa7127_state { |
236 | v4l2_std_id std; | 237 | v4l2_std_id std; |
237 | enum v4l2_chip_ident ident; | 238 | u32 ident; |
238 | enum saa7127_input_type input_type; | 239 | enum saa7127_input_type input_type; |
239 | enum saa7127_output_type output_type; | 240 | enum saa7127_output_type output_type; |
240 | int video_enable; | 241 | int video_enable; |
@@ -550,12 +551,12 @@ static int saa7127_command(struct i2c_client *client, | |||
550 | struct v4l2_routing *route = arg; | 551 | struct v4l2_routing *route = arg; |
551 | 552 | ||
552 | switch (cmd) { | 553 | switch (cmd) { |
553 | case VIDIOC_S_STD: | 554 | case VIDIOC_INT_S_STD_OUTPUT: |
554 | if (state->std == *(v4l2_std_id *)arg) | 555 | if (state->std == *(v4l2_std_id *)arg) |
555 | break; | 556 | break; |
556 | return saa7127_set_std(client, *(v4l2_std_id *)arg); | 557 | return saa7127_set_std(client, *(v4l2_std_id *)arg); |
557 | 558 | ||
558 | case VIDIOC_G_STD: | 559 | case VIDIOC_INT_G_STD_OUTPUT: |
559 | *(v4l2_std_id *)arg = state->std; | 560 | *(v4l2_std_id *)arg = state->std; |
560 | break; | 561 | break; |
561 | 562 | ||
@@ -650,9 +651,8 @@ static int saa7127_command(struct i2c_client *client, | |||
650 | break; | 651 | break; |
651 | } | 652 | } |
652 | 653 | ||
653 | case VIDIOC_INT_G_CHIP_IDENT: | 654 | case VIDIOC_G_CHIP_IDENT: |
654 | *(enum v4l2_chip_ident *)arg = state->ident; | 655 | return v4l2_chip_ident_i2c_client(client, arg, state->ident, 0); |
655 | break; | ||
656 | 656 | ||
657 | default: | 657 | default: |
658 | return -EINVAL; | 658 | return -EINVAL; |
diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig index 59da79ce2efd..309dca368f4a 100644 --- a/drivers/media/video/saa7134/Kconfig +++ b/drivers/media/video/saa7134/Kconfig | |||
@@ -46,6 +46,7 @@ config VIDEO_SAA7134_DVB | |||
46 | select DVB_NXT200X if !DVB_FE_CUSTOMISE | 46 | select DVB_NXT200X if !DVB_FE_CUSTOMISE |
47 | select DVB_TDA10086 if !DVB_FE_CUSTOMISE | 47 | select DVB_TDA10086 if !DVB_FE_CUSTOMISE |
48 | select DVB_TDA826X if !DVB_FE_CUSTOMISE | 48 | select DVB_TDA826X if !DVB_FE_CUSTOMISE |
49 | select DVB_TDA827X if !DVB_FE_CUSTOMISE | ||
49 | select DVB_ISL6421 if !DVB_FE_CUSTOMISE | 50 | select DVB_ISL6421 if !DVB_FE_CUSTOMISE |
50 | ---help--- | 51 | ---help--- |
51 | This adds support for DVB cards based on the | 52 | This adds support for DVB cards based on the |
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 89f32107f46b..4ea479baee74 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c | |||
@@ -1543,12 +1543,12 @@ struct saa7134_board saa7134_boards[] = { | |||
1543 | },{ | 1543 | },{ |
1544 | .name = name_comp1, | 1544 | .name = name_comp1, |
1545 | .vmux = 0, | 1545 | .vmux = 0, |
1546 | .amux = LINE2, | 1546 | .amux = LINE1, |
1547 | .gpio = 0x02, | 1547 | .gpio = 0x02, |
1548 | },{ | 1548 | },{ |
1549 | .name = name_svideo, | 1549 | .name = name_svideo, |
1550 | .vmux = 6, | 1550 | .vmux = 6, |
1551 | .amux = LINE2, | 1551 | .amux = LINE1, |
1552 | .gpio = 0x02, | 1552 | .gpio = 0x02, |
1553 | }}, | 1553 | }}, |
1554 | .radio = { | 1554 | .radio = { |
@@ -1778,17 +1778,19 @@ struct saa7134_board saa7134_boards[] = { | |||
1778 | [SAA7134_BOARD_FLYDVBTDUO] = { | 1778 | [SAA7134_BOARD_FLYDVBTDUO] = { |
1779 | /* LifeView FlyDVB-T DUO */ | 1779 | /* LifeView FlyDVB-T DUO */ |
1780 | /* "Nico Sabbi <nsabbi@tiscali.it> Hartmut Hackmann hartmut.hackmann@t-online.de*/ | 1780 | /* "Nico Sabbi <nsabbi@tiscali.it> Hartmut Hackmann hartmut.hackmann@t-online.de*/ |
1781 | .name = "LifeView FlyDVB-T DUO", | 1781 | .name = "LifeView FlyDVB-T DUO / MSI TV@nywhere Duo", |
1782 | .audio_clock = 0x00200000, | 1782 | .audio_clock = 0x00200000, |
1783 | .tuner_type = TUNER_PHILIPS_TDA8290, | 1783 | .tuner_type = TUNER_PHILIPS_TDA8290, |
1784 | .radio_type = UNSET, | 1784 | .radio_type = UNSET, |
1785 | .tuner_addr = ADDR_UNSET, | 1785 | .tuner_addr = ADDR_UNSET, |
1786 | .radio_addr = ADDR_UNSET, | 1786 | .radio_addr = ADDR_UNSET, |
1787 | .gpiomask = 0x00200000, | ||
1787 | .mpeg = SAA7134_MPEG_DVB, | 1788 | .mpeg = SAA7134_MPEG_DVB, |
1788 | .inputs = {{ | 1789 | .inputs = {{ |
1789 | .name = name_tv, | 1790 | .name = name_tv, |
1790 | .vmux = 1, | 1791 | .vmux = 1, |
1791 | .amux = TV, | 1792 | .amux = TV, |
1793 | .gpio = 0x200000, /* GPIO21=High for TV input */ | ||
1792 | .tv = 1, | 1794 | .tv = 1, |
1793 | },{ | 1795 | },{ |
1794 | .name = name_comp1, /* Composite signal on S-Video input */ | 1796 | .name = name_comp1, /* Composite signal on S-Video input */ |
@@ -1803,6 +1805,11 @@ struct saa7134_board saa7134_boards[] = { | |||
1803 | .vmux = 8, | 1805 | .vmux = 8, |
1804 | .amux = LINE2, | 1806 | .amux = LINE2, |
1805 | }}, | 1807 | }}, |
1808 | .radio = { | ||
1809 | .name = name_radio, | ||
1810 | .amux = TV, | ||
1811 | .gpio = 0x000000, /* GPIO21=Low for FM radio antenna */ | ||
1812 | }, | ||
1806 | }, | 1813 | }, |
1807 | [SAA7134_BOARD_PHILIPS_TOUGH] = { | 1814 | [SAA7134_BOARD_PHILIPS_TOUGH] = { |
1808 | .name = "Philips TOUGH DVB-T reference design", | 1815 | .name = "Philips TOUGH DVB-T reference design", |
@@ -2546,8 +2553,9 @@ struct saa7134_board saa7134_boards[] = { | |||
2546 | .radio_type = UNSET, | 2553 | .radio_type = UNSET, |
2547 | .tuner_addr = ADDR_UNSET, | 2554 | .tuner_addr = ADDR_UNSET, |
2548 | .radio_addr = ADDR_UNSET, | 2555 | .radio_addr = ADDR_UNSET, |
2556 | .tuner_config = 0, | ||
2549 | .mpeg = SAA7134_MPEG_DVB, | 2557 | .mpeg = SAA7134_MPEG_DVB, |
2550 | .gpiomask = 1 << 21, | 2558 | .gpiomask = 0x0200000, |
2551 | .inputs = {{ | 2559 | .inputs = {{ |
2552 | .name = name_tv, | 2560 | .name = name_tv, |
2553 | .vmux = 1, | 2561 | .vmux = 1, |
@@ -2624,7 +2632,7 @@ struct saa7134_board saa7134_boards[] = { | |||
2624 | }}, | 2632 | }}, |
2625 | .radio = { | 2633 | .radio = { |
2626 | .name = name_radio, | 2634 | .name = name_radio, |
2627 | .amux = LINE1, | 2635 | .amux = TV, |
2628 | .gpio = 0x0200000, | 2636 | .gpio = 0x0200000, |
2629 | }, | 2637 | }, |
2630 | }, | 2638 | }, |
@@ -3043,6 +3051,7 @@ struct saa7134_board saa7134_boards[] = { | |||
3043 | .radio_type = UNSET, | 3051 | .radio_type = UNSET, |
3044 | .tuner_addr = ADDR_UNSET, | 3052 | .tuner_addr = ADDR_UNSET, |
3045 | .radio_addr = ADDR_UNSET, | 3053 | .radio_addr = ADDR_UNSET, |
3054 | .tuner_config = 1, | ||
3046 | .mpeg = SAA7134_MPEG_DVB, | 3055 | .mpeg = SAA7134_MPEG_DVB, |
3047 | .gpiomask = 0x000200000, | 3056 | .gpiomask = 0x000200000, |
3048 | .inputs = {{ | 3057 | .inputs = {{ |
@@ -3289,6 +3298,115 @@ struct saa7134_board saa7134_boards[] = { | |||
3289 | .amux = LINE1, | 3298 | .amux = LINE1, |
3290 | }}, | 3299 | }}, |
3291 | }, | 3300 | }, |
3301 | [SAA7134_BOARD_PHILIPS_TIGER_S] = { | ||
3302 | .name = "Philips Tiger - S Reference design", | ||
3303 | .audio_clock = 0x00187de7, | ||
3304 | .tuner_type = TUNER_PHILIPS_TDA8290, | ||
3305 | .radio_type = UNSET, | ||
3306 | .tuner_addr = ADDR_UNSET, | ||
3307 | .radio_addr = ADDR_UNSET, | ||
3308 | .tuner_config = 2, | ||
3309 | .mpeg = SAA7134_MPEG_DVB, | ||
3310 | .gpiomask = 0x0200000, | ||
3311 | .inputs = {{ | ||
3312 | .name = name_tv, | ||
3313 | .vmux = 1, | ||
3314 | .amux = TV, | ||
3315 | .tv = 1, | ||
3316 | },{ | ||
3317 | .name = name_comp1, | ||
3318 | .vmux = 3, | ||
3319 | .amux = LINE1, | ||
3320 | },{ | ||
3321 | .name = name_svideo, | ||
3322 | .vmux = 8, | ||
3323 | .amux = LINE1, | ||
3324 | }}, | ||
3325 | .radio = { | ||
3326 | .name = name_radio, | ||
3327 | .amux = TV, | ||
3328 | .gpio = 0x0200000, | ||
3329 | }, | ||
3330 | }, | ||
3331 | [SAA7134_BOARD_AVERMEDIA_M102] = { | ||
3332 | .name = "Avermedia M102", | ||
3333 | .audio_clock = 0x00187de7, | ||
3334 | .tuner_type = TUNER_PHILIPS_TDA8290, | ||
3335 | .radio_type = UNSET, | ||
3336 | .tuner_addr = ADDR_UNSET, | ||
3337 | .radio_addr = ADDR_UNSET, | ||
3338 | .gpiomask = 1<<21, | ||
3339 | .inputs = {{ | ||
3340 | .name = name_tv, | ||
3341 | .vmux = 1, | ||
3342 | .amux = TV, | ||
3343 | .tv = 1, | ||
3344 | },{ | ||
3345 | .name = name_comp1, | ||
3346 | .vmux = 0, | ||
3347 | .amux = LINE2, | ||
3348 | },{ | ||
3349 | .name = name_svideo, | ||
3350 | .vmux = 6, | ||
3351 | .amux = LINE2, | ||
3352 | }}, | ||
3353 | }, | ||
3354 | [SAA7134_BOARD_ASUS_P7131_4871] = { | ||
3355 | .name = "ASUS P7131 4871", | ||
3356 | .audio_clock = 0x00187de7, | ||
3357 | .tuner_type = TUNER_PHILIPS_TDA8290, | ||
3358 | .radio_type = UNSET, | ||
3359 | .tuner_addr = ADDR_UNSET, | ||
3360 | .radio_addr = ADDR_UNSET, | ||
3361 | .tuner_config = 2, | ||
3362 | .mpeg = SAA7134_MPEG_DVB, | ||
3363 | .gpiomask = 0x0200000, | ||
3364 | .inputs = {{ | ||
3365 | .name = name_tv, | ||
3366 | .vmux = 1, | ||
3367 | .amux = TV, | ||
3368 | .tv = 1, | ||
3369 | .gpio = 0x0200000, | ||
3370 | }}, | ||
3371 | }, | ||
3372 | [SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA] = { | ||
3373 | .name = "ASUSTeK P7131 Hybrid", | ||
3374 | .audio_clock = 0x00187de7, | ||
3375 | .tuner_type = TUNER_PHILIPS_TDA8290, | ||
3376 | .radio_type = UNSET, | ||
3377 | .tuner_addr = ADDR_UNSET, | ||
3378 | .radio_addr = ADDR_UNSET, | ||
3379 | .tuner_config = 2, | ||
3380 | .gpiomask = 1 << 21, | ||
3381 | .mpeg = SAA7134_MPEG_DVB, | ||
3382 | .inputs = {{ | ||
3383 | .name = name_tv, | ||
3384 | .vmux = 1, | ||
3385 | .amux = TV, | ||
3386 | .tv = 1, | ||
3387 | .gpio = 0x0000000, | ||
3388 | },{ | ||
3389 | .name = name_comp1, | ||
3390 | .vmux = 3, | ||
3391 | .amux = LINE2, | ||
3392 | .gpio = 0x0200000, | ||
3393 | },{ | ||
3394 | .name = name_comp2, | ||
3395 | .vmux = 0, | ||
3396 | .amux = LINE2, | ||
3397 | .gpio = 0x0200000, | ||
3398 | },{ | ||
3399 | .name = name_svideo, | ||
3400 | .vmux = 8, | ||
3401 | .amux = LINE2, | ||
3402 | .gpio = 0x0200000, | ||
3403 | }}, | ||
3404 | .radio = { | ||
3405 | .name = name_radio, | ||
3406 | .amux = TV, | ||
3407 | .gpio = 0x0200000, | ||
3408 | }, | ||
3409 | }, | ||
3292 | }; | 3410 | }; |
3293 | 3411 | ||
3294 | const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards); | 3412 | const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards); |
@@ -3914,7 +4032,7 @@ struct pci_device_id saa7134_pci_tbl[] = { | |||
3914 | .device = PCI_DEVICE_ID_PHILIPS_SAA7133, | 4032 | .device = PCI_DEVICE_ID_PHILIPS_SAA7133, |
3915 | .subvendor = 0x1043, | 4033 | .subvendor = 0x1043, |
3916 | .subdevice = 0x4876, | 4034 | .subdevice = 0x4876, |
3917 | .driver_data = SAA7134_BOARD_ASUSTeK_P7131_DUAL, | 4035 | .driver_data = SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA, |
3918 | },{ | 4036 | },{ |
3919 | .vendor = PCI_VENDOR_ID_PHILIPS, | 4037 | .vendor = PCI_VENDOR_ID_PHILIPS, |
3920 | .device = PCI_DEVICE_ID_PHILIPS_SAA7133, | 4038 | .device = PCI_DEVICE_ID_PHILIPS_SAA7133, |
@@ -3958,6 +4076,30 @@ struct pci_device_id saa7134_pci_tbl[] = { | |||
3958 | .subdevice = 0x1175, | 4076 | .subdevice = 0x1175, |
3959 | .driver_data = SAA7134_BOARD_CINERGY_HT_PCI, | 4077 | .driver_data = SAA7134_BOARD_CINERGY_HT_PCI, |
3960 | },{ | 4078 | },{ |
4079 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
4080 | .device = PCI_DEVICE_ID_PHILIPS_SAA7133, | ||
4081 | .subvendor = 0x1461, /* Avermedia Technologies Inc */ | ||
4082 | .subdevice = 0xf31e, | ||
4083 | .driver_data = SAA7134_BOARD_AVERMEDIA_M102, | ||
4084 | },{ | ||
4085 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
4086 | .device = PCI_DEVICE_ID_PHILIPS_SAA7133, | ||
4087 | .subvendor = 0x4E42, /* MSI */ | ||
4088 | .subdevice = 0x0306, /* TV@nywhere DUO */ | ||
4089 | .driver_data = SAA7134_BOARD_FLYDVBTDUO, | ||
4090 | },{ | ||
4091 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
4092 | .device = PCI_DEVICE_ID_PHILIPS_SAA7133, | ||
4093 | .subvendor = 0x1043, | ||
4094 | .subdevice = 0x4871, | ||
4095 | .driver_data = SAA7134_BOARD_ASUS_P7131_4871, | ||
4096 | },{ | ||
4097 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
4098 | .device = PCI_DEVICE_ID_PHILIPS_SAA7133, | ||
4099 | .subvendor = 0x1043, | ||
4100 | .subdevice = 0x4857, | ||
4101 | .driver_data = SAA7134_BOARD_ASUSTeK_P7131_DUAL, | ||
4102 | },{ | ||
3961 | /* --- boards without eeprom + subsystem ID --- */ | 4103 | /* --- boards without eeprom + subsystem ID --- */ |
3962 | .vendor = PCI_VENDOR_ID_PHILIPS, | 4104 | .vendor = PCI_VENDOR_ID_PHILIPS, |
3963 | .device = PCI_DEVICE_ID_PHILIPS_SAA7134, | 4105 | .device = PCI_DEVICE_ID_PHILIPS_SAA7134, |
@@ -3971,7 +4113,6 @@ struct pci_device_id saa7134_pci_tbl[] = { | |||
3971 | .subdevice = 0, | 4113 | .subdevice = 0, |
3972 | .driver_data = SAA7134_BOARD_NOAUTO, | 4114 | .driver_data = SAA7134_BOARD_NOAUTO, |
3973 | },{ | 4115 | },{ |
3974 | |||
3975 | /* --- default catch --- */ | 4116 | /* --- default catch --- */ |
3976 | .vendor = PCI_VENDOR_ID_PHILIPS, | 4117 | .vendor = PCI_VENDOR_ID_PHILIPS, |
3977 | .device = PCI_DEVICE_ID_PHILIPS_SAA7130, | 4118 | .device = PCI_DEVICE_ID_PHILIPS_SAA7130, |
@@ -4063,6 +4204,7 @@ int saa7134_board_init1(struct saa7134_dev *dev) | |||
4063 | case SAA7134_BOARD_SEDNA_PC_TV_CARDBUS: | 4204 | case SAA7134_BOARD_SEDNA_PC_TV_CARDBUS: |
4064 | case SAA7134_BOARD_FLYDVBT_LR301: | 4205 | case SAA7134_BOARD_FLYDVBT_LR301: |
4065 | case SAA7134_BOARD_ASUSTeK_P7131_DUAL: | 4206 | case SAA7134_BOARD_ASUSTeK_P7131_DUAL: |
4207 | case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA: | ||
4066 | case SAA7134_BOARD_FLYDVBTDUO: | 4208 | case SAA7134_BOARD_FLYDVBTDUO: |
4067 | case SAA7134_BOARD_PROTEUS_2309: | 4209 | case SAA7134_BOARD_PROTEUS_2309: |
4068 | case SAA7134_BOARD_AVERMEDIA_A16AR: | 4210 | case SAA7134_BOARD_AVERMEDIA_A16AR: |
@@ -4103,8 +4245,8 @@ int saa7134_board_init1(struct saa7134_dev *dev) | |||
4103 | break; | 4245 | break; |
4104 | case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331: | 4246 | case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331: |
4105 | case SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS: | 4247 | case SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS: |
4106 | saa_writeb(SAA7134_GPIO_GPMODE3, 0x08); | 4248 | saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x08000000, 0x08000000); |
4107 | saa_writeb(SAA7134_GPIO_GPSTATUS3, 0x00); | 4249 | saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x08000000, 0x00000000); |
4108 | break; | 4250 | break; |
4109 | case SAA7134_BOARD_AVERMEDIA_CARDBUS: | 4251 | case SAA7134_BOARD_AVERMEDIA_CARDBUS: |
4110 | /* power-up tuner chip */ | 4252 | /* power-up tuner chip */ |
@@ -4137,6 +4279,11 @@ int saa7134_board_init1(struct saa7134_dev *dev) | |||
4137 | "%s: Dual decoder functionality is disabled for now, use the other chip.\n", | 4279 | "%s: Dual decoder functionality is disabled for now, use the other chip.\n", |
4138 | dev->name,card(dev).name,dev->name,dev->name); | 4280 | dev->name,card(dev).name,dev->name,dev->name); |
4139 | break; | 4281 | break; |
4282 | case SAA7134_BOARD_AVERMEDIA_M102: | ||
4283 | /* enable tuner */ | ||
4284 | saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x8c040007, 0x8c040007); | ||
4285 | saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0c0007cd, 0x0c0007cd); | ||
4286 | break; | ||
4140 | } | 4287 | } |
4141 | return 0; | 4288 | return 0; |
4142 | } | 4289 | } |
@@ -4146,6 +4293,9 @@ int saa7134_board_init2(struct saa7134_dev *dev) | |||
4146 | { | 4293 | { |
4147 | unsigned char buf; | 4294 | unsigned char buf; |
4148 | int board; | 4295 | int board; |
4296 | struct tuner_setup tun_setup; | ||
4297 | tun_setup.config = 0; | ||
4298 | tun_setup.tuner_callback = saa7134_tuner_callback; | ||
4149 | 4299 | ||
4150 | switch (dev->board) { | 4300 | switch (dev->board) { |
4151 | case SAA7134_BOARD_BMK_MPEX_NOTUNER: | 4301 | case SAA7134_BOARD_BMK_MPEX_NOTUNER: |
@@ -4162,8 +4312,6 @@ int saa7134_board_init2(struct saa7134_dev *dev) | |||
4162 | dev->tuner_type = saa7134_boards[dev->board].tuner_type; | 4312 | dev->tuner_type = saa7134_boards[dev->board].tuner_type; |
4163 | 4313 | ||
4164 | if (TUNER_ABSENT != dev->tuner_type) { | 4314 | if (TUNER_ABSENT != dev->tuner_type) { |
4165 | struct tuner_setup tun_setup; | ||
4166 | |||
4167 | tun_setup.mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV; | 4315 | tun_setup.mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV; |
4168 | tun_setup.type = dev->tuner_type; | 4316 | tun_setup.type = dev->tuner_type; |
4169 | tun_setup.addr = ADDR_UNSET; | 4317 | tun_setup.addr = ADDR_UNSET; |
@@ -4173,7 +4321,6 @@ int saa7134_board_init2(struct saa7134_dev *dev) | |||
4173 | break; | 4321 | break; |
4174 | case SAA7134_BOARD_MD7134: | 4322 | case SAA7134_BOARD_MD7134: |
4175 | { | 4323 | { |
4176 | struct tuner_setup tun_setup; | ||
4177 | u8 subaddr; | 4324 | u8 subaddr; |
4178 | u8 data[3]; | 4325 | u8 data[3]; |
4179 | int ret, tuner_t; | 4326 | int ret, tuner_t; |
@@ -4245,7 +4392,6 @@ int saa7134_board_init2(struct saa7134_dev *dev) | |||
4245 | * the channel decoder. We have to make it transparent to find it | 4392 | * the channel decoder. We have to make it transparent to find it |
4246 | */ | 4393 | */ |
4247 | { | 4394 | { |
4248 | struct tuner_setup tun_setup; | ||
4249 | u8 data[] = { 0x07, 0x02}; | 4395 | u8 data[] = { 0x07, 0x02}; |
4250 | struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; | 4396 | struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; |
4251 | i2c_transfer(&dev->i2c_adap, &msg, 1); | 4397 | i2c_transfer(&dev->i2c_adap, &msg, 1); |
@@ -4258,16 +4404,38 @@ int saa7134_board_init2(struct saa7134_dev *dev) | |||
4258 | } | 4404 | } |
4259 | break; | 4405 | break; |
4260 | case SAA7134_BOARD_PHILIPS_TIGER: | 4406 | case SAA7134_BOARD_PHILIPS_TIGER: |
4407 | case SAA7134_BOARD_PHILIPS_TIGER_S: | ||
4408 | { | ||
4409 | u8 data[] = { 0x3c, 0x33, 0x60}; | ||
4410 | struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; | ||
4411 | if(dev->autodetected && (dev->eedata[0x49] == 0x50)) { | ||
4412 | dev->board = SAA7134_BOARD_PHILIPS_TIGER_S; | ||
4413 | printk(KERN_INFO "%s: Reconfigured board as %s\n", | ||
4414 | dev->name, saa7134_boards[dev->board].name); | ||
4415 | } | ||
4416 | if(dev->board == SAA7134_BOARD_PHILIPS_TIGER_S) { | ||
4417 | tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV; | ||
4418 | tun_setup.type = TUNER_PHILIPS_TDA8290; | ||
4419 | tun_setup.addr = 0x4b; | ||
4420 | tun_setup.config = 2; | ||
4421 | |||
4422 | saa7134_i2c_call_clients (dev, TUNER_SET_TYPE_ADDR,&tun_setup); | ||
4423 | data[2] = 0x68; | ||
4424 | } | ||
4425 | i2c_transfer(&dev->i2c_adap, &msg, 1); | ||
4426 | } | ||
4427 | break; | ||
4261 | case SAA7134_BOARD_PINNACLE_PCTV_310i: | 4428 | case SAA7134_BOARD_PINNACLE_PCTV_310i: |
4262 | case SAA7134_BOARD_TEVION_DVBT_220RF: | 4429 | case SAA7134_BOARD_TEVION_DVBT_220RF: |
4263 | case SAA7134_BOARD_ASUSTeK_P7131_DUAL: | 4430 | case SAA7134_BOARD_ASUSTeK_P7131_DUAL: |
4431 | case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA: | ||
4264 | case SAA7134_BOARD_MEDION_MD8800_QUADRO: | 4432 | case SAA7134_BOARD_MEDION_MD8800_QUADRO: |
4265 | case SAA7134_BOARD_HAUPPAUGE_HVR1110: | 4433 | case SAA7134_BOARD_HAUPPAUGE_HVR1110: |
4266 | /* this is a hybrid board, initialize to analog mode | 4434 | /* this is a hybrid board, initialize to analog mode |
4267 | * and configure firmware eeprom address | 4435 | * and configure firmware eeprom address |
4268 | */ | 4436 | */ |
4269 | { | 4437 | { |
4270 | u8 data[] = { 0x3c, 0x33, 0x68}; | 4438 | u8 data[] = { 0x3c, 0x33, 0x60}; |
4271 | struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; | 4439 | struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; |
4272 | i2c_transfer(&dev->i2c_adap, &msg, 1); | 4440 | i2c_transfer(&dev->i2c_adap, &msg, 1); |
4273 | } | 4441 | } |
@@ -4281,18 +4449,18 @@ int saa7134_board_init2(struct saa7134_dev *dev) | |||
4281 | break; | 4449 | break; |
4282 | case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331: | 4450 | case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331: |
4283 | case SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS: | 4451 | case SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS: |
4284 | /* make the tda10046 find its eeprom */ | 4452 | /* initialize analog mode */ |
4285 | { | 4453 | { |
4286 | u8 data[] = { 0x3c, 0x33, 0x62}; | 4454 | u8 data[] = { 0x3c, 0x33, 0x6a}; |
4287 | struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; | 4455 | struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; |
4288 | i2c_transfer(&dev->i2c_adap, &msg, 1); | 4456 | i2c_transfer(&dev->i2c_adap, &msg, 1); |
4289 | } | 4457 | } |
4290 | break; | 4458 | break; |
4291 | case SAA7134_BOARD_CINERGY_HT_PCMCIA: | 4459 | case SAA7134_BOARD_CINERGY_HT_PCMCIA: |
4292 | case SAA7134_BOARD_CINERGY_HT_PCI: | 4460 | case SAA7134_BOARD_CINERGY_HT_PCI: |
4293 | /* make the tda10046 find its eeprom */ | 4461 | /* initialize analog mode */ |
4294 | { | 4462 | { |
4295 | u8 data[] = { 0x3c, 0x33, 0x60}; | 4463 | u8 data[] = { 0x3c, 0x33, 0x68}; |
4296 | struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; | 4464 | struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; |
4297 | i2c_transfer(&dev->i2c_adap, &msg, 1); | 4465 | i2c_transfer(&dev->i2c_adap, &msg, 1); |
4298 | } | 4466 | } |
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index ed038fff3b4f..25f84701a8e8 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c | |||
@@ -117,6 +117,64 @@ void saa7134_track_gpio(struct saa7134_dev *dev, char *msg) | |||
117 | dev->name, mode, (~mode) & status, mode & status, msg); | 117 | dev->name, mode, (~mode) & status, mode & status, msg); |
118 | } | 118 | } |
119 | 119 | ||
120 | void saa7134_set_gpio(struct saa7134_dev *dev, int bit_no, int value) | ||
121 | { | ||
122 | u32 index, bitval; | ||
123 | |||
124 | index = 1 << bit_no; | ||
125 | switch (value) { | ||
126 | case 0: /* static value */ | ||
127 | case 1: dprintk("setting GPIO%d to static %d\n", bit_no, value); | ||
128 | /* turn sync mode off if necessary */ | ||
129 | if (index & 0x00c00000) | ||
130 | saa_andorb(SAA7134_VIDEO_PORT_CTRL6, 0x0f, 0x00); | ||
131 | if (value) | ||
132 | bitval = index; | ||
133 | else | ||
134 | bitval = 0; | ||
135 | saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, index, index); | ||
136 | saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, index, bitval); | ||
137 | break; | ||
138 | case 3: /* tristate */ | ||
139 | dprintk("setting GPIO%d to tristate\n", bit_no); | ||
140 | saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, index, 0); | ||
141 | break; | ||
142 | } | ||
143 | } | ||
144 | |||
145 | int saa7134_tuner_callback(void *ptr, int command, int arg) | ||
146 | { | ||
147 | u8 sync_control; | ||
148 | struct saa7134_dev *dev = ptr; | ||
149 | |||
150 | switch (dev->tuner_type) { | ||
151 | case TUNER_PHILIPS_TDA8290: | ||
152 | switch (command) { | ||
153 | case 0: /* switch LNA gain through GPIO 22*/ | ||
154 | saa7134_set_gpio(dev, 22, arg) ; | ||
155 | break; | ||
156 | case 1: /* vsync output at GPIO22. 50 / 60Hz */ | ||
157 | dprintk("setting GPIO22 to vsync %d\n", arg); | ||
158 | saa_andorb(SAA7134_VIDEO_PORT_CTRL3, 0x80, 0x80); | ||
159 | saa_andorb(SAA7134_VIDEO_PORT_CTRL6, 0x0f, 0x03); | ||
160 | if (arg == 1) | ||
161 | sync_control = 11; | ||
162 | else | ||
163 | sync_control = 17; | ||
164 | saa_writeb(SAA7134_VGATE_START, sync_control); | ||
165 | saa_writeb(SAA7134_VGATE_STOP, sync_control + 1); | ||
166 | saa_andorb(SAA7134_MISC_VGATE_MSB, 0x03, 0x00); | ||
167 | break; | ||
168 | default: | ||
169 | return -EINVAL; | ||
170 | } | ||
171 | break; | ||
172 | default: | ||
173 | return -ENODEV; | ||
174 | } | ||
175 | return 0; | ||
176 | } | ||
177 | |||
120 | /* ------------------------------------------------------------------ */ | 178 | /* ------------------------------------------------------------------ */ |
121 | 179 | ||
122 | 180 | ||
@@ -124,55 +182,28 @@ void saa7134_track_gpio(struct saa7134_dev *dev, char *msg) | |||
124 | /* delayed request_module */ | 182 | /* delayed request_module */ |
125 | 183 | ||
126 | #if defined(CONFIG_MODULES) && defined(MODULE) | 184 | #if defined(CONFIG_MODULES) && defined(MODULE) |
127 | static int need_empress; | ||
128 | static int need_dvb; | ||
129 | static int need_alsa; | ||
130 | static int need_oss; | ||
131 | 185 | ||
132 | static int pending_call(struct notifier_block *self, unsigned long state, | ||
133 | void *module) | ||
134 | { | ||
135 | if (module != THIS_MODULE || state != MODULE_STATE_LIVE) | ||
136 | return NOTIFY_DONE; | ||
137 | 186 | ||
138 | if (need_empress) | 187 | static void request_module_async(struct work_struct *work){ |
188 | struct saa7134_dev* dev = container_of(work, struct saa7134_dev, request_module_wk); | ||
189 | if (card_is_empress(dev)) | ||
139 | request_module("saa7134-empress"); | 190 | request_module("saa7134-empress"); |
140 | if (need_dvb) | 191 | if (card_is_dvb(dev)) |
141 | request_module("saa7134-dvb"); | 192 | request_module("saa7134-dvb"); |
142 | if (need_alsa) | 193 | if (alsa) |
143 | request_module("saa7134-alsa"); | 194 | request_module("saa7134-alsa"); |
144 | if (need_oss) | 195 | if (oss) |
145 | request_module("saa7134-oss"); | 196 | request_module("saa7134-oss"); |
146 | return NOTIFY_DONE; | ||
147 | } | 197 | } |
148 | 198 | ||
149 | static int pending_registered; | 199 | static void request_submodules(struct saa7134_dev *dev) |
150 | static struct notifier_block pending_notifier = { | ||
151 | .notifier_call = pending_call, | ||
152 | }; | ||
153 | |||
154 | static void request_module_depend(char *name, int *flag) | ||
155 | { | 200 | { |
156 | int err; | 201 | INIT_WORK(&dev->request_module_wk, request_module_async); |
157 | switch (THIS_MODULE->state) { | 202 | schedule_work(&dev->request_module_wk); |
158 | case MODULE_STATE_COMING: | ||
159 | if (!pending_registered) { | ||
160 | err = register_module_notifier(&pending_notifier); | ||
161 | pending_registered = 1; | ||
162 | } | ||
163 | *flag = 1; | ||
164 | break; | ||
165 | case MODULE_STATE_LIVE: | ||
166 | request_module(name); | ||
167 | break; | ||
168 | default: | ||
169 | /* nothing */; | ||
170 | break; | ||
171 | } | ||
172 | } | 203 | } |
173 | 204 | ||
174 | #else | 205 | #else |
175 | #define request_module_depend(name,flag) | 206 | #define request_submodules(dev) |
176 | #endif /* CONFIG_MODULES */ | 207 | #endif /* CONFIG_MODULES */ |
177 | 208 | ||
178 | /* ------------------------------------------------------------------ */ | 209 | /* ------------------------------------------------------------------ */ |
@@ -703,7 +734,6 @@ static int saa7134_hwfini(struct saa7134_dev *dev) | |||
703 | saa7134_ts_fini(dev); | 734 | saa7134_ts_fini(dev); |
704 | saa7134_input_fini(dev); | 735 | saa7134_input_fini(dev); |
705 | saa7134_vbi_fini(dev); | 736 | saa7134_vbi_fini(dev); |
706 | saa7134_video_fini(dev); | ||
707 | saa7134_tvaudio_fini(dev); | 737 | saa7134_tvaudio_fini(dev); |
708 | return 0; | 738 | return 0; |
709 | } | 739 | } |
@@ -944,18 +974,9 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, | |||
944 | request_module("tuner"); | 974 | request_module("tuner"); |
945 | if (card_is_empress(dev)) { | 975 | if (card_is_empress(dev)) { |
946 | request_module("saa6752hs"); | 976 | request_module("saa6752hs"); |
947 | request_module_depend("saa7134-empress",&need_empress); | ||
948 | } | 977 | } |
949 | 978 | ||
950 | if (card_is_dvb(dev)) | 979 | request_submodules(dev); |
951 | request_module_depend("saa7134-dvb",&need_dvb); | ||
952 | |||
953 | |||
954 | if (alsa) | ||
955 | request_module_depend("saa7134-alsa",&need_alsa); | ||
956 | |||
957 | if (oss) | ||
958 | request_module_depend("saa7134-oss",&need_oss); | ||
959 | 980 | ||
960 | v4l2_prio_init(&dev->prio); | 981 | v4l2_prio_init(&dev->prio); |
961 | 982 | ||
@@ -1013,6 +1034,9 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, | |||
1013 | saa7134_dmasound_init(dev); | 1034 | saa7134_dmasound_init(dev); |
1014 | } | 1035 | } |
1015 | 1036 | ||
1037 | if (TUNER_ABSENT != dev->tuner_type) | ||
1038 | saa7134_i2c_call_clients(dev, TUNER_SET_STANDBY, NULL); | ||
1039 | |||
1016 | return 0; | 1040 | return 0; |
1017 | 1041 | ||
1018 | fail4: | 1042 | fail4: |
@@ -1152,10 +1176,6 @@ static int saa7134_init(void) | |||
1152 | 1176 | ||
1153 | static void saa7134_fini(void) | 1177 | static void saa7134_fini(void) |
1154 | { | 1178 | { |
1155 | #if defined(CONFIG_MODULES) && defined(MODULE) | ||
1156 | if (pending_registered) | ||
1157 | unregister_module_notifier(&pending_notifier); | ||
1158 | #endif /* CONFIG_MODULES */ | ||
1159 | pci_unregister_driver(&saa7134_pci_driver); | 1179 | pci_unregister_driver(&saa7134_pci_driver); |
1160 | } | 1180 | } |
1161 | 1181 | ||
@@ -1164,6 +1184,7 @@ module_exit(saa7134_fini); | |||
1164 | 1184 | ||
1165 | /* ----------------------------------------------------------- */ | 1185 | /* ----------------------------------------------------------- */ |
1166 | 1186 | ||
1187 | EXPORT_SYMBOL(saa7134_set_gpio); | ||
1167 | EXPORT_SYMBOL(saa7134_i2c_call_clients); | 1188 | EXPORT_SYMBOL(saa7134_i2c_call_clients); |
1168 | EXPORT_SYMBOL(saa7134_devlist); | 1189 | EXPORT_SYMBOL(saa7134_devlist); |
1169 | EXPORT_SYMBOL(saa7134_boards); | 1190 | EXPORT_SYMBOL(saa7134_boards); |
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index e3059fd33951..65aec881bbde 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c | |||
@@ -41,7 +41,9 @@ | |||
41 | 41 | ||
42 | #include "tda10086.h" | 42 | #include "tda10086.h" |
43 | #include "tda826x.h" | 43 | #include "tda826x.h" |
44 | #include "tda827x.h" | ||
44 | #include "isl6421.h" | 45 | #include "isl6421.h" |
46 | |||
45 | MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]"); | 47 | MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]"); |
46 | MODULE_LICENSE("GPL"); | 48 | MODULE_LICENSE("GPL"); |
47 | 49 | ||
@@ -54,7 +56,21 @@ static int use_frontend = 0; | |||
54 | module_param(use_frontend, int, 0644); | 56 | module_param(use_frontend, int, 0644); |
55 | MODULE_PARM_DESC(use_frontend,"for cards with multiple frontends (0: terrestrial, 1: satellite)"); | 57 | MODULE_PARM_DESC(use_frontend,"for cards with multiple frontends (0: terrestrial, 1: satellite)"); |
56 | 58 | ||
57 | /* ------------------------------------------------------------------ */ | 59 | static int debug = 0; |
60 | module_param(debug, int, 0644); | ||
61 | MODULE_PARM_DESC(debug, "Turn on/off module debugging (default:off)."); | ||
62 | |||
63 | #define dprintk(fmt, arg...) do { if (debug) \ | ||
64 | printk(KERN_DEBUG "%s/dvb: " fmt, dev->name , ## arg); } while(0) | ||
65 | |||
66 | /* Print a warning */ | ||
67 | #define wprintk(fmt, arg...) \ | ||
68 | printk(KERN_WARNING "%s/dvb: " fmt, dev->name, ## arg) | ||
69 | |||
70 | /* ------------------------------------------------------------------ | ||
71 | * mt352 based DVB-T cards | ||
72 | */ | ||
73 | |||
58 | static int pinnacle_antenna_pwr(struct saa7134_dev *dev, int on) | 74 | static int pinnacle_antenna_pwr(struct saa7134_dev *dev, int on) |
59 | { | 75 | { |
60 | u32 ok; | 76 | u32 ok; |
@@ -75,8 +91,7 @@ static int pinnacle_antenna_pwr(struct saa7134_dev *dev, int on) | |||
75 | saa_setl(SAA7134_GPIO_GPSTATUS0 >> 2, (1 << 28)); | 91 | saa_setl(SAA7134_GPIO_GPSTATUS0 >> 2, (1 << 28)); |
76 | udelay(10); | 92 | udelay(10); |
77 | ok = saa_readl(SAA7134_GPIO_GPSTATUS0) & (1 << 27); | 93 | ok = saa_readl(SAA7134_GPIO_GPSTATUS0) & (1 << 27); |
78 | printk("%s: %s %s\n", dev->name, __FUNCTION__, | 94 | dprintk("%s %s\n", __FUNCTION__, ok ? "on" : "off"); |
79 | ok ? "on" : "off"); | ||
80 | 95 | ||
81 | if (!ok) | 96 | if (!ok) |
82 | saa_clearl(SAA7134_GPIO_GPSTATUS0 >> 2, (1 << 26)); | 97 | saa_clearl(SAA7134_GPIO_GPSTATUS0 >> 2, (1 << 26)); |
@@ -96,7 +111,7 @@ static int mt352_pinnacle_init(struct dvb_frontend* fe) | |||
96 | static u8 irq_cfg [] = { INTERRUPT_EN_0, 0x00, 0x00, 0x00, 0x00 }; | 111 | static u8 irq_cfg [] = { INTERRUPT_EN_0, 0x00, 0x00, 0x00, 0x00 }; |
97 | struct saa7134_dev *dev= fe->dvb->priv; | 112 | struct saa7134_dev *dev= fe->dvb->priv; |
98 | 113 | ||
99 | printk("%s: %s called\n",dev->name,__FUNCTION__); | 114 | dprintk("%s called\n", __FUNCTION__); |
100 | 115 | ||
101 | mt352_write(fe, clock_config, sizeof(clock_config)); | 116 | mt352_write(fe, clock_config, sizeof(clock_config)); |
102 | udelay(200); | 117 | udelay(200); |
@@ -185,10 +200,26 @@ static struct mt352_config avermedia_777 = { | |||
185 | .demod_init = mt352_aver777_init, | 200 | .demod_init = mt352_aver777_init, |
186 | }; | 201 | }; |
187 | 202 | ||
188 | /* ------------------------------------------------------------------ */ | 203 | /* ================================================================== |
189 | static int philips_tda6651_pll_set(u8 addr, struct dvb_frontend *fe, struct dvb_frontend_parameters *params) | 204 | * tda1004x based DVB-T cards, helper functions |
205 | */ | ||
206 | |||
207 | static int philips_tda1004x_request_firmware(struct dvb_frontend *fe, | ||
208 | const struct firmware **fw, char *name) | ||
209 | { | ||
210 | struct saa7134_dev *dev = fe->dvb->priv; | ||
211 | return request_firmware(fw, name, &dev->pci->dev); | ||
212 | } | ||
213 | |||
214 | /* ------------------------------------------------------------------ | ||
215 | * these tuners are tu1216, td1316(a) | ||
216 | */ | ||
217 | |||
218 | static int philips_tda6651_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) | ||
190 | { | 219 | { |
191 | struct saa7134_dev *dev = fe->dvb->priv; | 220 | struct saa7134_dev *dev = fe->dvb->priv; |
221 | struct tda1004x_state *state = fe->demodulator_priv; | ||
222 | u8 addr = state->config->tuner_address; | ||
192 | u8 tuner_buf[4]; | 223 | u8 tuner_buf[4]; |
193 | struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tuner_buf,.len = | 224 | struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tuner_buf,.len = |
194 | sizeof(tuner_buf) }; | 225 | sizeof(tuner_buf) }; |
@@ -263,15 +294,20 @@ static int philips_tda6651_pll_set(u8 addr, struct dvb_frontend *fe, struct dvb_ | |||
263 | 294 | ||
264 | if (fe->ops.i2c_gate_ctrl) | 295 | if (fe->ops.i2c_gate_ctrl) |
265 | fe->ops.i2c_gate_ctrl(fe, 1); | 296 | fe->ops.i2c_gate_ctrl(fe, 1); |
266 | if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1) | 297 | if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1) { |
298 | wprintk("could not write to tuner at addr: 0x%02x\n", | ||
299 | addr << 1); | ||
267 | return -EIO; | 300 | return -EIO; |
301 | } | ||
268 | msleep(1); | 302 | msleep(1); |
269 | return 0; | 303 | return 0; |
270 | } | 304 | } |
271 | 305 | ||
272 | static int philips_tda6651_pll_init(u8 addr, struct dvb_frontend *fe) | 306 | static int philips_tu1216_init(struct dvb_frontend *fe) |
273 | { | 307 | { |
274 | struct saa7134_dev *dev = fe->dvb->priv; | 308 | struct saa7134_dev *dev = fe->dvb->priv; |
309 | struct tda1004x_state *state = fe->demodulator_priv; | ||
310 | u8 addr = state->config->tuner_address; | ||
275 | static u8 tu1216_init[] = { 0x0b, 0xf5, 0x85, 0xab }; | 311 | static u8 tu1216_init[] = { 0x0b, 0xf5, 0x85, 0xab }; |
276 | struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tu1216_init,.len = sizeof(tu1216_init) }; | 312 | struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tu1216_init,.len = sizeof(tu1216_init) }; |
277 | 313 | ||
@@ -287,46 +323,17 @@ static int philips_tda6651_pll_init(u8 addr, struct dvb_frontend *fe) | |||
287 | 323 | ||
288 | /* ------------------------------------------------------------------ */ | 324 | /* ------------------------------------------------------------------ */ |
289 | 325 | ||
290 | static int philips_tu1216_tuner_60_init(struct dvb_frontend *fe) | ||
291 | { | ||
292 | return philips_tda6651_pll_init(0x60, fe); | ||
293 | } | ||
294 | |||
295 | static int philips_tu1216_tuner_60_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) | ||
296 | { | ||
297 | return philips_tda6651_pll_set(0x60, fe, params); | ||
298 | } | ||
299 | |||
300 | static int philips_tda1004x_request_firmware(struct dvb_frontend *fe, | ||
301 | const struct firmware **fw, char *name) | ||
302 | { | ||
303 | struct saa7134_dev *dev = fe->dvb->priv; | ||
304 | return request_firmware(fw, name, &dev->pci->dev); | ||
305 | } | ||
306 | |||
307 | static struct tda1004x_config philips_tu1216_60_config = { | 326 | static struct tda1004x_config philips_tu1216_60_config = { |
308 | |||
309 | .demod_address = 0x8, | 327 | .demod_address = 0x8, |
310 | .invert = 1, | 328 | .invert = 1, |
311 | .invert_oclk = 0, | 329 | .invert_oclk = 0, |
312 | .xtal_freq = TDA10046_XTAL_4M, | 330 | .xtal_freq = TDA10046_XTAL_4M, |
313 | .agc_config = TDA10046_AGC_DEFAULT, | 331 | .agc_config = TDA10046_AGC_DEFAULT, |
314 | .if_freq = TDA10046_FREQ_3617, | 332 | .if_freq = TDA10046_FREQ_3617, |
315 | .request_firmware = philips_tda1004x_request_firmware, | 333 | .tuner_address = 0x60, |
334 | .request_firmware = philips_tda1004x_request_firmware | ||
316 | }; | 335 | }; |
317 | 336 | ||
318 | /* ------------------------------------------------------------------ */ | ||
319 | |||
320 | static int philips_tu1216_tuner_61_init(struct dvb_frontend *fe) | ||
321 | { | ||
322 | return philips_tda6651_pll_init(0x61, fe); | ||
323 | } | ||
324 | |||
325 | static int philips_tu1216_tuner_61_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) | ||
326 | { | ||
327 | return philips_tda6651_pll_set(0x61, fe, params); | ||
328 | } | ||
329 | |||
330 | static struct tda1004x_config philips_tu1216_61_config = { | 337 | static struct tda1004x_config philips_tu1216_61_config = { |
331 | 338 | ||
332 | .demod_address = 0x8, | 339 | .demod_address = 0x8, |
@@ -335,7 +342,8 @@ static struct tda1004x_config philips_tu1216_61_config = { | |||
335 | .xtal_freq = TDA10046_XTAL_4M, | 342 | .xtal_freq = TDA10046_XTAL_4M, |
336 | .agc_config = TDA10046_AGC_DEFAULT, | 343 | .agc_config = TDA10046_AGC_DEFAULT, |
337 | .if_freq = TDA10046_FREQ_3617, | 344 | .if_freq = TDA10046_FREQ_3617, |
338 | .request_firmware = philips_tda1004x_request_firmware, | 345 | .tuner_address = 0x61, |
346 | .request_firmware = philips_tda1004x_request_firmware | ||
339 | }; | 347 | }; |
340 | 348 | ||
341 | /* ------------------------------------------------------------------ */ | 349 | /* ------------------------------------------------------------------ */ |
@@ -343,24 +351,42 @@ static struct tda1004x_config philips_tu1216_61_config = { | |||
343 | static int philips_td1316_tuner_init(struct dvb_frontend *fe) | 351 | static int philips_td1316_tuner_init(struct dvb_frontend *fe) |
344 | { | 352 | { |
345 | struct saa7134_dev *dev = fe->dvb->priv; | 353 | struct saa7134_dev *dev = fe->dvb->priv; |
354 | struct tda1004x_state *state = fe->demodulator_priv; | ||
355 | u8 addr = state->config->tuner_address; | ||
346 | static u8 msg[] = { 0x0b, 0xf5, 0x86, 0xab }; | 356 | static u8 msg[] = { 0x0b, 0xf5, 0x86, 0xab }; |
347 | struct i2c_msg init_msg = {.addr = 0x61,.flags = 0,.buf = msg,.len = sizeof(msg) }; | 357 | struct i2c_msg init_msg = {.addr = addr,.flags = 0,.buf = msg,.len = sizeof(msg) }; |
348 | 358 | ||
349 | /* setup PLL configuration */ | 359 | /* setup PLL configuration */ |
350 | if (fe->ops.i2c_gate_ctrl) | 360 | if (fe->ops.i2c_gate_ctrl) |
351 | fe->ops.i2c_gate_ctrl(fe, 1); | 361 | fe->ops.i2c_gate_ctrl(fe, 1); |
352 | if (i2c_transfer(&dev->i2c_adap, &init_msg, 1) != 1) | 362 | if (i2c_transfer(&dev->i2c_adap, &init_msg, 1) != 1) |
353 | return -EIO; | 363 | return -EIO; |
354 | if (fe->ops.i2c_gate_ctrl) | ||
355 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
356 | return 0; | 364 | return 0; |
357 | } | 365 | } |
358 | 366 | ||
359 | static int philips_td1316_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) | 367 | static int philips_td1316_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) |
360 | { | 368 | { |
361 | return philips_tda6651_pll_set(0x61, fe, params); | 369 | return philips_tda6651_pll_set(fe, params); |
362 | } | 370 | } |
363 | 371 | ||
372 | static int philips_td1316_tuner_sleep(struct dvb_frontend *fe) | ||
373 | { | ||
374 | struct saa7134_dev *dev = fe->dvb->priv; | ||
375 | struct tda1004x_state *state = fe->demodulator_priv; | ||
376 | u8 addr = state->config->tuner_address; | ||
377 | static u8 msg[] = { 0x0b, 0xdc, 0x86, 0xa4 }; | ||
378 | struct i2c_msg analog_msg = {.addr = addr,.flags = 0,.buf = msg,.len = sizeof(msg) }; | ||
379 | |||
380 | /* switch the tuner to analog mode */ | ||
381 | if (fe->ops.i2c_gate_ctrl) | ||
382 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
383 | if (i2c_transfer(&dev->i2c_adap, &analog_msg, 1) != 1) | ||
384 | return -EIO; | ||
385 | return 0; | ||
386 | } | ||
387 | |||
388 | /* ------------------------------------------------------------------ */ | ||
389 | |||
364 | static int philips_europa_tuner_init(struct dvb_frontend *fe) | 390 | static int philips_europa_tuner_init(struct dvb_frontend *fe) |
365 | { | 391 | { |
366 | struct saa7134_dev *dev = fe->dvb->priv; | 392 | struct saa7134_dev *dev = fe->dvb->priv; |
@@ -380,18 +406,14 @@ static int philips_europa_tuner_init(struct dvb_frontend *fe) | |||
380 | static int philips_europa_tuner_sleep(struct dvb_frontend *fe) | 406 | static int philips_europa_tuner_sleep(struct dvb_frontend *fe) |
381 | { | 407 | { |
382 | struct saa7134_dev *dev = fe->dvb->priv; | 408 | struct saa7134_dev *dev = fe->dvb->priv; |
383 | /* this message actually turns the tuner back to analog mode */ | ||
384 | static u8 msg[] = { 0x0b, 0xdc, 0x86, 0xa4 }; | ||
385 | struct i2c_msg analog_msg = {.addr = 0x61,.flags = 0,.buf = msg,.len = sizeof(msg) }; | ||
386 | 409 | ||
387 | i2c_transfer(&dev->i2c_adap, &analog_msg, 1); | 410 | static u8 msg[] = { 0x00, 0x14 }; |
388 | msleep(1); | 411 | struct i2c_msg analog_msg = {.addr = 0x43,.flags = 0,.buf = msg,.len = sizeof(msg) }; |
412 | |||
413 | if (philips_td1316_tuner_sleep(fe)) | ||
414 | return -EIO; | ||
389 | 415 | ||
390 | /* switch the board to analog mode */ | 416 | /* switch the board to analog mode */ |
391 | analog_msg.addr = 0x43; | ||
392 | analog_msg.len = 0x02; | ||
393 | msg[0] = 0x00; | ||
394 | msg[1] = 0x14; | ||
395 | if (fe->ops.i2c_gate_ctrl) | 417 | if (fe->ops.i2c_gate_ctrl) |
396 | fe->ops.i2c_gate_ctrl(fe, 1); | 418 | fe->ops.i2c_gate_ctrl(fe, 1); |
397 | i2c_transfer(&dev->i2c_adap, &analog_msg, 1); | 419 | i2c_transfer(&dev->i2c_adap, &analog_msg, 1); |
@@ -416,7 +438,8 @@ static struct tda1004x_config philips_europa_config = { | |||
416 | .xtal_freq = TDA10046_XTAL_4M, | 438 | .xtal_freq = TDA10046_XTAL_4M, |
417 | .agc_config = TDA10046_AGC_IFO_AUTO_POS, | 439 | .agc_config = TDA10046_AGC_IFO_AUTO_POS, |
418 | .if_freq = TDA10046_FREQ_052, | 440 | .if_freq = TDA10046_FREQ_052, |
419 | .request_firmware = NULL, | 441 | .tuner_address = 0x61, |
442 | .request_firmware = philips_tda1004x_request_firmware | ||
420 | }; | 443 | }; |
421 | 444 | ||
422 | /* ------------------------------------------------------------------ */ | 445 | /* ------------------------------------------------------------------ */ |
@@ -424,9 +447,11 @@ static struct tda1004x_config philips_europa_config = { | |||
424 | static int philips_fmd1216_tuner_init(struct dvb_frontend *fe) | 447 | static int philips_fmd1216_tuner_init(struct dvb_frontend *fe) |
425 | { | 448 | { |
426 | struct saa7134_dev *dev = fe->dvb->priv; | 449 | struct saa7134_dev *dev = fe->dvb->priv; |
450 | struct tda1004x_state *state = fe->demodulator_priv; | ||
451 | u8 addr = state->config->tuner_address; | ||
427 | /* this message is to set up ATC and ALC */ | 452 | /* this message is to set up ATC and ALC */ |
428 | static u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0xa0 }; | 453 | static u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0xa0 }; |
429 | struct i2c_msg tuner_msg = {.addr = 0x61,.flags = 0,.buf = fmd1216_init,.len = sizeof(fmd1216_init) }; | 454 | struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = fmd1216_init,.len = sizeof(fmd1216_init) }; |
430 | 455 | ||
431 | if (fe->ops.i2c_gate_ctrl) | 456 | if (fe->ops.i2c_gate_ctrl) |
432 | fe->ops.i2c_gate_ctrl(fe, 1); | 457 | fe->ops.i2c_gate_ctrl(fe, 1); |
@@ -440,9 +465,11 @@ static int philips_fmd1216_tuner_init(struct dvb_frontend *fe) | |||
440 | static int philips_fmd1216_tuner_sleep(struct dvb_frontend *fe) | 465 | static int philips_fmd1216_tuner_sleep(struct dvb_frontend *fe) |
441 | { | 466 | { |
442 | struct saa7134_dev *dev = fe->dvb->priv; | 467 | struct saa7134_dev *dev = fe->dvb->priv; |
468 | struct tda1004x_state *state = fe->demodulator_priv; | ||
469 | u8 addr = state->config->tuner_address; | ||
443 | /* this message actually turns the tuner back to analog mode */ | 470 | /* this message actually turns the tuner back to analog mode */ |
444 | static u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0x60 }; | 471 | u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0x60 }; |
445 | struct i2c_msg tuner_msg = {.addr = 0x61,.flags = 0,.buf = fmd1216_init,.len = sizeof(fmd1216_init) }; | 472 | struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = fmd1216_init,.len = sizeof(fmd1216_init) }; |
446 | 473 | ||
447 | if (fe->ops.i2c_gate_ctrl) | 474 | if (fe->ops.i2c_gate_ctrl) |
448 | fe->ops.i2c_gate_ctrl(fe, 1); | 475 | fe->ops.i2c_gate_ctrl(fe, 1); |
@@ -460,8 +487,10 @@ static int philips_fmd1216_tuner_sleep(struct dvb_frontend *fe) | |||
460 | static int philips_fmd1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) | 487 | static int philips_fmd1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) |
461 | { | 488 | { |
462 | struct saa7134_dev *dev = fe->dvb->priv; | 489 | struct saa7134_dev *dev = fe->dvb->priv; |
490 | struct tda1004x_state *state = fe->demodulator_priv; | ||
491 | u8 addr = state->config->tuner_address; | ||
463 | u8 tuner_buf[4]; | 492 | u8 tuner_buf[4]; |
464 | struct i2c_msg tuner_msg = {.addr = 0x61,.flags = 0,.buf = tuner_buf,.len = | 493 | struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tuner_buf,.len = |
465 | sizeof(tuner_buf) }; | 494 | sizeof(tuner_buf) }; |
466 | int tuner_frequency = 0; | 495 | int tuner_frequency = 0; |
467 | int divider = 0; | 496 | int divider = 0; |
@@ -536,8 +565,11 @@ static int philips_fmd1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_ | |||
536 | 565 | ||
537 | if (fe->ops.i2c_gate_ctrl) | 566 | if (fe->ops.i2c_gate_ctrl) |
538 | fe->ops.i2c_gate_ctrl(fe, 1); | 567 | fe->ops.i2c_gate_ctrl(fe, 1); |
539 | if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1) | 568 | if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1) { |
569 | wprintk("could not write to tuner at addr: 0x%02x\n", | ||
570 | addr << 1); | ||
540 | return -EIO; | 571 | return -EIO; |
572 | } | ||
541 | return 0; | 573 | return 0; |
542 | } | 574 | } |
543 | 575 | ||
@@ -548,582 +580,365 @@ static struct tda1004x_config medion_cardbus = { | |||
548 | .xtal_freq = TDA10046_XTAL_16M, | 580 | .xtal_freq = TDA10046_XTAL_16M, |
549 | .agc_config = TDA10046_AGC_IFO_AUTO_NEG, | 581 | .agc_config = TDA10046_AGC_IFO_AUTO_NEG, |
550 | .if_freq = TDA10046_FREQ_3613, | 582 | .if_freq = TDA10046_FREQ_3613, |
551 | .request_firmware = NULL, | 583 | .tuner_address = 0x61, |
584 | .request_firmware = philips_tda1004x_request_firmware | ||
552 | }; | 585 | }; |
553 | 586 | ||
554 | /* ------------------------------------------------------------------ */ | 587 | /* ------------------------------------------------------------------ |
555 | 588 | * tda 1004x based cards with philips silicon tuner | |
556 | struct tda827x_data { | 589 | */ |
557 | u32 lomax; | ||
558 | u8 spd; | ||
559 | u8 bs; | ||
560 | u8 bp; | ||
561 | u8 cp; | ||
562 | u8 gc3; | ||
563 | u8 div1p5; | ||
564 | }; | ||
565 | |||
566 | static struct tda827x_data tda827x_dvbt[] = { | ||
567 | { .lomax = 62000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, | ||
568 | { .lomax = 66000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, | ||
569 | { .lomax = 76000000, .spd = 3, .bs = 1, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, | ||
570 | { .lomax = 84000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, | ||
571 | { .lomax = 93000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
572 | { .lomax = 98000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
573 | { .lomax = 109000000, .spd = 3, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
574 | { .lomax = 123000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1}, | ||
575 | { .lomax = 133000000, .spd = 2, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1}, | ||
576 | { .lomax = 151000000, .spd = 2, .bs = 1, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
577 | { .lomax = 154000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
578 | { .lomax = 181000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 0, .div1p5 = 0}, | ||
579 | { .lomax = 185000000, .spd = 2, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
580 | { .lomax = 217000000, .spd = 2, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
581 | { .lomax = 244000000, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1}, | ||
582 | { .lomax = 265000000, .spd = 1, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1}, | ||
583 | { .lomax = 302000000, .spd = 1, .bs = 1, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
584 | { .lomax = 324000000, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
585 | { .lomax = 370000000, .spd = 1, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
586 | { .lomax = 454000000, .spd = 1, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
587 | { .lomax = 493000000, .spd = 0, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1}, | ||
588 | { .lomax = 530000000, .spd = 0, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1}, | ||
589 | { .lomax = 554000000, .spd = 0, .bs = 1, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
590 | { .lomax = 604000000, .spd = 0, .bs = 1, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, | ||
591 | { .lomax = 696000000, .spd = 0, .bs = 2, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, | ||
592 | { .lomax = 740000000, .spd = 0, .bs = 2, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0}, | ||
593 | { .lomax = 820000000, .spd = 0, .bs = 3, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, | ||
594 | { .lomax = 865000000, .spd = 0, .bs = 3, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0}, | ||
595 | { .lomax = 0, .spd = 0, .bs = 0, .bp = 0, .cp = 0, .gc3 = 0, .div1p5 = 0} | ||
596 | }; | ||
597 | |||
598 | static int philips_tda827x_tuner_init(struct dvb_frontend *fe) | ||
599 | { | ||
600 | return 0; | ||
601 | } | ||
602 | 590 | ||
603 | static int philips_tda827x_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) | 591 | static void philips_tda827x_lna_gain(struct dvb_frontend *fe, int high) |
604 | { | 592 | { |
605 | struct saa7134_dev *dev = fe->dvb->priv; | 593 | struct saa7134_dev *dev = fe->dvb->priv; |
606 | u8 tuner_buf[14]; | 594 | struct tda1004x_state *state = fe->demodulator_priv; |
607 | 595 | u8 addr = state->config->i2c_gate; | |
608 | struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tuner_buf, | 596 | u8 config = state->config->tuner_config; |
609 | .len = sizeof(tuner_buf) }; | 597 | u8 GP00_CF[] = {0x20, 0x01}; |
610 | int i, tuner_freq, if_freq; | 598 | u8 GP00_LEV[] = {0x22, 0x00}; |
611 | u32 N; | 599 | |
612 | switch (params->u.ofdm.bandwidth) { | 600 | struct i2c_msg msg = {.addr = addr,.flags = 0,.buf = GP00_CF, .len = 2}; |
613 | case BANDWIDTH_6_MHZ: | 601 | if (config) { |
614 | if_freq = 4000000; | 602 | if (high) { |
615 | break; | 603 | dprintk("setting LNA to high gain\n"); |
616 | case BANDWIDTH_7_MHZ: | 604 | } else { |
617 | if_freq = 4500000; | 605 | dprintk("setting LNA to low gain\n"); |
618 | break; | 606 | } |
619 | default: /* 8 MHz or Auto */ | ||
620 | if_freq = 5000000; | ||
621 | break; | ||
622 | } | ||
623 | tuner_freq = params->frequency + if_freq; | ||
624 | |||
625 | i = 0; | ||
626 | while (tda827x_dvbt[i].lomax < tuner_freq) { | ||
627 | if(tda827x_dvbt[i + 1].lomax == 0) | ||
628 | break; | ||
629 | i++; | ||
630 | } | 607 | } |
631 | 608 | switch (config) { | |
632 | N = ((tuner_freq + 125000) / 250000) << (tda827x_dvbt[i].spd + 2); | 609 | case 0: /* no LNA */ |
633 | tuner_buf[0] = 0; | ||
634 | tuner_buf[1] = (N>>8) | 0x40; | ||
635 | tuner_buf[2] = N & 0xff; | ||
636 | tuner_buf[3] = 0; | ||
637 | tuner_buf[4] = 0x52; | ||
638 | tuner_buf[5] = (tda827x_dvbt[i].spd << 6) + (tda827x_dvbt[i].div1p5 << 5) + | ||
639 | (tda827x_dvbt[i].bs << 3) + tda827x_dvbt[i].bp; | ||
640 | tuner_buf[6] = (tda827x_dvbt[i].gc3 << 4) + 0x8f; | ||
641 | tuner_buf[7] = 0xbf; | ||
642 | tuner_buf[8] = 0x2a; | ||
643 | tuner_buf[9] = 0x05; | ||
644 | tuner_buf[10] = 0xff; | ||
645 | tuner_buf[11] = 0x00; | ||
646 | tuner_buf[12] = 0x00; | ||
647 | tuner_buf[13] = 0x40; | ||
648 | |||
649 | tuner_msg.len = 14; | ||
650 | if (fe->ops.i2c_gate_ctrl) | ||
651 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
652 | if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1) | ||
653 | return -EIO; | ||
654 | |||
655 | msleep(500); | ||
656 | /* correct CP value */ | ||
657 | tuner_buf[0] = 0x30; | ||
658 | tuner_buf[1] = 0x50 + tda827x_dvbt[i].cp; | ||
659 | tuner_msg.len = 2; | ||
660 | if (fe->ops.i2c_gate_ctrl) | ||
661 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
662 | i2c_transfer(&dev->i2c_adap, &tuner_msg, 1); | ||
663 | |||
664 | return 0; | ||
665 | } | ||
666 | |||
667 | static int philips_tda827x_tuner_sleep(struct dvb_frontend *fe) | ||
668 | { | ||
669 | struct saa7134_dev *dev = fe->dvb->priv; | ||
670 | static u8 tda827x_sleep[] = { 0x30, 0xd0}; | ||
671 | struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tda827x_sleep, | ||
672 | .len = sizeof(tda827x_sleep) }; | ||
673 | if (fe->ops.i2c_gate_ctrl) | ||
674 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
675 | i2c_transfer(&dev->i2c_adap, &tuner_msg, 1); | ||
676 | return 0; | ||
677 | } | ||
678 | |||
679 | static struct tda1004x_config tda827x_lifeview_config = { | ||
680 | .demod_address = 0x08, | ||
681 | .invert = 1, | ||
682 | .invert_oclk = 0, | ||
683 | .xtal_freq = TDA10046_XTAL_16M, | ||
684 | .agc_config = TDA10046_AGC_TDA827X_GP11, | ||
685 | .if_freq = TDA10046_FREQ_045, | ||
686 | .request_firmware = NULL, | ||
687 | }; | ||
688 | |||
689 | /* ------------------------------------------------------------------ */ | ||
690 | |||
691 | struct tda827xa_data { | ||
692 | u32 lomax; | ||
693 | u8 svco; | ||
694 | u8 spd; | ||
695 | u8 scr; | ||
696 | u8 sbs; | ||
697 | u8 gc3; | ||
698 | }; | ||
699 | |||
700 | static struct tda827xa_data tda827xa_dvbt[] = { | ||
701 | { .lomax = 56875000, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 1}, | ||
702 | { .lomax = 67250000, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1}, | ||
703 | { .lomax = 81250000, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1}, | ||
704 | { .lomax = 97500000, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1}, | ||
705 | { .lomax = 113750000, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1}, | ||
706 | { .lomax = 134500000, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, | ||
707 | { .lomax = 154000000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, | ||
708 | { .lomax = 162500000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, | ||
709 | { .lomax = 183000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, | ||
710 | { .lomax = 195000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1}, | ||
711 | { .lomax = 227500000, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1}, | ||
712 | { .lomax = 269000000, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1}, | ||
713 | { .lomax = 290000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1}, | ||
714 | { .lomax = 325000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1}, | ||
715 | { .lomax = 390000000, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1}, | ||
716 | { .lomax = 455000000, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1}, | ||
717 | { .lomax = 520000000, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, | ||
718 | { .lomax = 538000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1}, | ||
719 | { .lomax = 550000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, | ||
720 | { .lomax = 620000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, | ||
721 | { .lomax = 650000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, | ||
722 | { .lomax = 700000000, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, | ||
723 | { .lomax = 780000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, | ||
724 | { .lomax = 820000000, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, | ||
725 | { .lomax = 870000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, | ||
726 | { .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0}, | ||
727 | { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0}}; | ||
728 | |||
729 | |||
730 | static int philips_tda827xa_pll_set(u8 addr, struct dvb_frontend *fe, struct dvb_frontend_parameters *params) | ||
731 | { | ||
732 | struct saa7134_dev *dev = fe->dvb->priv; | ||
733 | u8 tuner_buf[14]; | ||
734 | unsigned char reg2[2]; | ||
735 | |||
736 | struct i2c_msg msg = {.addr = addr,.flags = 0,.buf = tuner_buf}; | ||
737 | int i, tuner_freq, if_freq; | ||
738 | u32 N; | ||
739 | |||
740 | switch (params->u.ofdm.bandwidth) { | ||
741 | case BANDWIDTH_6_MHZ: | ||
742 | if_freq = 4000000; | ||
743 | break; | 610 | break; |
744 | case BANDWIDTH_7_MHZ: | 611 | case 1: /* switch is GPIO 0 of tda8290 */ |
745 | if_freq = 4500000; | 612 | case 2: |
613 | /* turn Vsync off */ | ||
614 | saa7134_set_gpio(dev, 22, 0); | ||
615 | GP00_LEV[1] = high ? 0 : 1; | ||
616 | if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) { | ||
617 | wprintk("could not access tda8290 at addr: 0x%02x\n", | ||
618 | addr << 1); | ||
619 | return; | ||
620 | } | ||
621 | msg.buf = GP00_LEV; | ||
622 | if (config == 2) | ||
623 | GP00_LEV[1] = high ? 1 : 0; | ||
624 | i2c_transfer(&dev->i2c_adap, &msg, 1); | ||
746 | break; | 625 | break; |
747 | default: /* 8 MHz or Auto */ | 626 | case 3: /* switch with GPIO of saa713x */ |
748 | if_freq = 5000000; | 627 | saa7134_set_gpio(dev, 22, high); |
749 | break; | 628 | break; |
750 | } | 629 | } |
751 | tuner_freq = params->frequency + if_freq; | ||
752 | |||
753 | i = 0; | ||
754 | while (tda827xa_dvbt[i].lomax < tuner_freq) { | ||
755 | if(tda827xa_dvbt[i + 1].lomax == 0) | ||
756 | break; | ||
757 | i++; | ||
758 | } | ||
759 | |||
760 | N = ((tuner_freq + 31250) / 62500) << tda827xa_dvbt[i].spd; | ||
761 | tuner_buf[0] = 0; // subaddress | ||
762 | tuner_buf[1] = N >> 8; | ||
763 | tuner_buf[2] = N & 0xff; | ||
764 | tuner_buf[3] = 0; | ||
765 | tuner_buf[4] = 0x16; | ||
766 | tuner_buf[5] = (tda827xa_dvbt[i].spd << 5) + (tda827xa_dvbt[i].svco << 3) + | ||
767 | tda827xa_dvbt[i].sbs; | ||
768 | tuner_buf[6] = 0x4b + (tda827xa_dvbt[i].gc3 << 4); | ||
769 | tuner_buf[7] = 0x0c; | ||
770 | tuner_buf[8] = 0x06; | ||
771 | tuner_buf[9] = 0x24; | ||
772 | tuner_buf[10] = 0xff; | ||
773 | tuner_buf[11] = 0x60; | ||
774 | tuner_buf[12] = 0x00; | ||
775 | tuner_buf[13] = 0x39; // lpsel | ||
776 | msg.len = 14; | ||
777 | if (fe->ops.i2c_gate_ctrl) | ||
778 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
779 | if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) | ||
780 | return -EIO; | ||
781 | |||
782 | msg.buf= reg2; | ||
783 | msg.len = 2; | ||
784 | reg2[0] = 0x60; | ||
785 | reg2[1] = 0x3c; | ||
786 | if (fe->ops.i2c_gate_ctrl) | ||
787 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
788 | i2c_transfer(&dev->i2c_adap, &msg, 1); | ||
789 | |||
790 | reg2[0] = 0xa0; | ||
791 | reg2[1] = 0x40; | ||
792 | if (fe->ops.i2c_gate_ctrl) | ||
793 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
794 | i2c_transfer(&dev->i2c_adap, &msg, 1); | ||
795 | |||
796 | msleep(2); | ||
797 | /* correct CP value */ | ||
798 | reg2[0] = 0x30; | ||
799 | reg2[1] = 0x10 + tda827xa_dvbt[i].scr; | ||
800 | msg.len = 2; | ||
801 | if (fe->ops.i2c_gate_ctrl) | ||
802 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
803 | i2c_transfer(&dev->i2c_adap, &msg, 1); | ||
804 | |||
805 | msleep(550); | ||
806 | reg2[0] = 0x50; | ||
807 | reg2[1] = 0x4f + (tda827xa_dvbt[i].gc3 << 4); | ||
808 | if (fe->ops.i2c_gate_ctrl) | ||
809 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
810 | i2c_transfer(&dev->i2c_adap, &msg, 1); | ||
811 | |||
812 | return 0; | ||
813 | |||
814 | } | 630 | } |
815 | 631 | ||
816 | static int philips_tda827xa_tuner_sleep(u8 addr, struct dvb_frontend *fe) | 632 | static int tda8290_i2c_gate_ctrl( struct dvb_frontend* fe, int enable) |
817 | { | 633 | { |
818 | struct saa7134_dev *dev = fe->dvb->priv; | 634 | struct tda1004x_state *state = fe->demodulator_priv; |
819 | static u8 tda827xa_sleep[] = { 0x30, 0x90}; | ||
820 | struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tda827xa_sleep, | ||
821 | .len = sizeof(tda827xa_sleep) }; | ||
822 | if (fe->ops.i2c_gate_ctrl) | ||
823 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
824 | i2c_transfer(&dev->i2c_adap, &tuner_msg, 1); | ||
825 | if (fe->ops.i2c_gate_ctrl) | ||
826 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
827 | return 0; | ||
828 | } | ||
829 | 635 | ||
830 | /* ------------------------------------------------------------------ */ | 636 | u8 addr = state->config->i2c_gate; |
831 | |||
832 | static int tda8290_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) | ||
833 | { | ||
834 | struct saa7134_dev *dev = fe->dvb->priv; | ||
835 | static u8 tda8290_close[] = { 0x21, 0xc0}; | 637 | static u8 tda8290_close[] = { 0x21, 0xc0}; |
836 | static u8 tda8290_open[] = { 0x21, 0x80}; | 638 | static u8 tda8290_open[] = { 0x21, 0x80}; |
837 | struct i2c_msg tda8290_msg = {.addr = 0x4b,.flags = 0, .len = 2}; | 639 | struct i2c_msg tda8290_msg = {.addr = addr,.flags = 0, .len = 2}; |
838 | if (enable) { | 640 | if (enable) { |
839 | tda8290_msg.buf = tda8290_close; | 641 | tda8290_msg.buf = tda8290_close; |
840 | } else { | 642 | } else { |
841 | tda8290_msg.buf = tda8290_open; | 643 | tda8290_msg.buf = tda8290_open; |
842 | } | 644 | } |
843 | if (i2c_transfer(&dev->i2c_adap, &tda8290_msg, 1) != 1) | 645 | if (i2c_transfer(state->i2c, &tda8290_msg, 1) != 1) { |
646 | struct saa7134_dev *dev = fe->dvb->priv; | ||
647 | wprintk("could not access tda8290 I2C gate\n"); | ||
844 | return -EIO; | 648 | return -EIO; |
649 | } | ||
845 | msleep(20); | 650 | msleep(20); |
846 | return 0; | 651 | return 0; |
847 | } | 652 | } |
848 | 653 | ||
849 | /* ------------------------------------------------------------------ */ | 654 | /* ------------------------------------------------------------------ */ |
850 | 655 | ||
851 | static int philips_tiger_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) | 656 | static int philips_tda827x_tuner_init(struct dvb_frontend *fe) |
852 | { | 657 | { |
853 | int ret; | 658 | struct saa7134_dev *dev = fe->dvb->priv; |
659 | struct tda1004x_state *state = fe->demodulator_priv; | ||
854 | 660 | ||
855 | ret = philips_tda827xa_pll_set(0x61, fe, params); | 661 | switch (state->config->antenna_switch) { |
856 | if (ret != 0) | 662 | case 0: break; |
857 | return ret; | 663 | case 1: dprintk("setting GPIO21 to 0 (TV antenna?)\n"); |
664 | saa7134_set_gpio(dev, 21, 0); | ||
665 | break; | ||
666 | case 2: dprintk("setting GPIO21 to 1 (Radio antenna?)\n"); | ||
667 | saa7134_set_gpio(dev, 21, 1); | ||
668 | break; | ||
669 | } | ||
858 | return 0; | 670 | return 0; |
859 | } | 671 | } |
860 | 672 | ||
861 | static int philips_tiger_tuner_init(struct dvb_frontend *fe) | 673 | static int philips_tda827x_tuner_sleep(struct dvb_frontend *fe) |
862 | { | 674 | { |
863 | struct saa7134_dev *dev = fe->dvb->priv; | 675 | struct saa7134_dev *dev = fe->dvb->priv; |
864 | static u8 data[] = { 0x3c, 0x33, 0x6a}; | 676 | struct tda1004x_state *state = fe->demodulator_priv; |
865 | struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; | ||
866 | 677 | ||
867 | if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) | 678 | switch (state->config->antenna_switch) { |
868 | return -EIO; | 679 | case 0: break; |
680 | case 1: dprintk("setting GPIO21 to 1 (Radio antenna?)\n"); | ||
681 | saa7134_set_gpio(dev, 21, 1); | ||
682 | break; | ||
683 | case 2: dprintk("setting GPIO21 to 0 (TV antenna?)\n"); | ||
684 | saa7134_set_gpio(dev, 21, 0); | ||
685 | break; | ||
686 | } | ||
869 | return 0; | 687 | return 0; |
870 | } | 688 | } |
871 | 689 | ||
872 | static int philips_tiger_tuner_sleep(struct dvb_frontend *fe) | 690 | static struct tda827x_config tda827x_cfg = { |
873 | { | 691 | .lna_gain = philips_tda827x_lna_gain, |
874 | struct saa7134_dev *dev = fe->dvb->priv; | 692 | .init = philips_tda827x_tuner_init, |
875 | static u8 data[] = { 0x3c, 0x33, 0x68}; | 693 | .sleep = philips_tda827x_tuner_sleep |
876 | struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; | 694 | }; |
877 | 695 | ||
878 | i2c_transfer(&dev->i2c_adap, &msg, 1); | 696 | static void configure_tda827x_fe(struct saa7134_dev *dev, struct tda1004x_config *tda_conf) |
879 | philips_tda827xa_tuner_sleep( 0x61, fe); | 697 | { |
880 | return 0; | 698 | dev->dvb.frontend = dvb_attach(tda10046_attach, tda_conf, &dev->i2c_adap); |
699 | if (dev->dvb.frontend) { | ||
700 | if (tda_conf->i2c_gate) | ||
701 | dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl; | ||
702 | if (dvb_attach(tda827x_attach, dev->dvb.frontend, tda_conf->tuner_address, | ||
703 | &dev->i2c_adap,&tda827x_cfg) == NULL) { | ||
704 | wprintk("no tda827x tuner found at addr: %02x\n", | ||
705 | tda_conf->tuner_address); | ||
706 | } | ||
707 | } | ||
881 | } | 708 | } |
882 | 709 | ||
883 | static struct tda1004x_config philips_tiger_config = { | 710 | /* ------------------------------------------------------------------ */ |
711 | static struct tda1004x_config tda827x_lifeview_config = { | ||
884 | .demod_address = 0x08, | 712 | .demod_address = 0x08, |
885 | .invert = 1, | 713 | .invert = 1, |
886 | .invert_oclk = 0, | 714 | .invert_oclk = 0, |
887 | .xtal_freq = TDA10046_XTAL_16M, | 715 | .xtal_freq = TDA10046_XTAL_16M, |
888 | .agc_config = TDA10046_AGC_TDA827X_GP11, | 716 | .agc_config = TDA10046_AGC_TDA827X, |
717 | .gpio_config = TDA10046_GP11_I, | ||
889 | .if_freq = TDA10046_FREQ_045, | 718 | .if_freq = TDA10046_FREQ_045, |
890 | .request_firmware = NULL, | 719 | .tuner_address = 0x60, |
720 | .request_firmware = philips_tda1004x_request_firmware | ||
891 | }; | 721 | }; |
892 | /* ------------------------------------------------------------------ */ | ||
893 | |||
894 | static int cinergy_ht_tuner_init(struct dvb_frontend *fe) | ||
895 | { | ||
896 | struct saa7134_dev *dev = fe->dvb->priv; | ||
897 | static u8 data[] = { 0x3c, 0x33, 0x62}; | ||
898 | struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; | ||
899 | 722 | ||
900 | if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) | 723 | static struct tda1004x_config philips_tiger_config = { |
901 | return -EIO; | 724 | .demod_address = 0x08, |
902 | return 0; | 725 | .invert = 1, |
903 | } | 726 | .invert_oclk = 0, |
904 | 727 | .xtal_freq = TDA10046_XTAL_16M, | |
905 | static int cinergy_ht_tuner_sleep(struct dvb_frontend *fe) | 728 | .agc_config = TDA10046_AGC_TDA827X, |
906 | { | 729 | .gpio_config = TDA10046_GP11_I, |
907 | struct saa7134_dev *dev = fe->dvb->priv; | 730 | .if_freq = TDA10046_FREQ_045, |
908 | static u8 data[] = { 0x3c, 0x33, 0x60}; | 731 | .i2c_gate = 0x4b, |
909 | struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; | 732 | .tuner_address = 0x61, |
910 | 733 | .tuner_config = 0, | |
911 | i2c_transfer(&dev->i2c_adap, &msg, 1); | 734 | .antenna_switch= 1, |
912 | philips_tda827xa_tuner_sleep( 0x61, fe); | 735 | .request_firmware = philips_tda1004x_request_firmware |
913 | return 0; | 736 | }; |
914 | } | ||
915 | 737 | ||
916 | static struct tda1004x_config cinergy_ht_config = { | 738 | static struct tda1004x_config cinergy_ht_config = { |
917 | .demod_address = 0x08, | 739 | .demod_address = 0x08, |
918 | .invert = 1, | 740 | .invert = 1, |
919 | .invert_oclk = 0, | 741 | .invert_oclk = 0, |
920 | .xtal_freq = TDA10046_XTAL_16M, | 742 | .xtal_freq = TDA10046_XTAL_16M, |
921 | .agc_config = TDA10046_AGC_TDA827X_GP01, | 743 | .agc_config = TDA10046_AGC_TDA827X, |
744 | .gpio_config = TDA10046_GP01_I, | ||
922 | .if_freq = TDA10046_FREQ_045, | 745 | .if_freq = TDA10046_FREQ_045, |
923 | .request_firmware = NULL, | 746 | .i2c_gate = 0x4b, |
747 | .tuner_address = 0x61, | ||
748 | .tuner_config = 0, | ||
749 | .request_firmware = philips_tda1004x_request_firmware | ||
924 | }; | 750 | }; |
925 | 751 | ||
926 | /* ------------------------------------------------------------------ */ | 752 | static struct tda1004x_config cinergy_ht_pci_config = { |
753 | .demod_address = 0x08, | ||
754 | .invert = 1, | ||
755 | .invert_oclk = 0, | ||
756 | .xtal_freq = TDA10046_XTAL_16M, | ||
757 | .agc_config = TDA10046_AGC_TDA827X, | ||
758 | .gpio_config = TDA10046_GP01_I, | ||
759 | .if_freq = TDA10046_FREQ_045, | ||
760 | .i2c_gate = 0x4b, | ||
761 | .tuner_address = 0x60, | ||
762 | .tuner_config = 0, | ||
763 | .request_firmware = philips_tda1004x_request_firmware | ||
764 | }; | ||
927 | 765 | ||
928 | static struct tda1004x_config pinnacle_pctv_310i_config = { | 766 | static struct tda1004x_config philips_tiger_s_config = { |
929 | .demod_address = 0x08, | 767 | .demod_address = 0x08, |
930 | .invert = 1, | 768 | .invert = 1, |
931 | .invert_oclk = 0, | 769 | .invert_oclk = 0, |
932 | .xtal_freq = TDA10046_XTAL_16M, | 770 | .xtal_freq = TDA10046_XTAL_16M, |
933 | .agc_config = TDA10046_AGC_TDA827X_GP11, | 771 | .agc_config = TDA10046_AGC_TDA827X, |
772 | .gpio_config = TDA10046_GP01_I, | ||
934 | .if_freq = TDA10046_FREQ_045, | 773 | .if_freq = TDA10046_FREQ_045, |
935 | .request_firmware = philips_tda1004x_request_firmware, | 774 | .i2c_gate = 0x4b, |
775 | .tuner_address = 0x61, | ||
776 | .tuner_config = 2, | ||
777 | .antenna_switch= 1, | ||
778 | .request_firmware = philips_tda1004x_request_firmware | ||
936 | }; | 779 | }; |
937 | 780 | ||
938 | /* ------------------------------------------------------------------ */ | 781 | static struct tda1004x_config pinnacle_pctv_310i_config = { |
782 | .demod_address = 0x08, | ||
783 | .invert = 1, | ||
784 | .invert_oclk = 0, | ||
785 | .xtal_freq = TDA10046_XTAL_16M, | ||
786 | .agc_config = TDA10046_AGC_TDA827X, | ||
787 | .gpio_config = TDA10046_GP11_I, | ||
788 | .if_freq = TDA10046_FREQ_045, | ||
789 | .i2c_gate = 0x4b, | ||
790 | .tuner_address = 0x61, | ||
791 | .tuner_config = 1, | ||
792 | .request_firmware = philips_tda1004x_request_firmware | ||
793 | }; | ||
939 | 794 | ||
940 | static struct tda1004x_config hauppauge_hvr_1110_config = { | 795 | static struct tda1004x_config hauppauge_hvr_1110_config = { |
941 | .demod_address = 0x08, | 796 | .demod_address = 0x08, |
942 | .invert = 1, | 797 | .invert = 1, |
943 | .invert_oclk = 0, | 798 | .invert_oclk = 0, |
944 | .xtal_freq = TDA10046_XTAL_16M, | 799 | .xtal_freq = TDA10046_XTAL_16M, |
945 | .agc_config = TDA10046_AGC_TDA827X_GP11, | 800 | .agc_config = TDA10046_AGC_TDA827X, |
801 | .gpio_config = TDA10046_GP11_I, | ||
946 | .if_freq = TDA10046_FREQ_045, | 802 | .if_freq = TDA10046_FREQ_045, |
947 | .request_firmware = philips_tda1004x_request_firmware, | 803 | .i2c_gate = 0x4b, |
804 | .tuner_address = 0x61, | ||
805 | .request_firmware = philips_tda1004x_request_firmware | ||
948 | }; | 806 | }; |
949 | 807 | ||
950 | /* ------------------------------------------------------------------ */ | ||
951 | |||
952 | static struct tda1004x_config asus_p7131_dual_config = { | 808 | static struct tda1004x_config asus_p7131_dual_config = { |
953 | .demod_address = 0x08, | 809 | .demod_address = 0x08, |
954 | .invert = 1, | 810 | .invert = 1, |
955 | .invert_oclk = 0, | 811 | .invert_oclk = 0, |
956 | .xtal_freq = TDA10046_XTAL_16M, | 812 | .xtal_freq = TDA10046_XTAL_16M, |
957 | .agc_config = TDA10046_AGC_TDA827X_GP11, | 813 | .agc_config = TDA10046_AGC_TDA827X, |
814 | .gpio_config = TDA10046_GP11_I, | ||
958 | .if_freq = TDA10046_FREQ_045, | 815 | .if_freq = TDA10046_FREQ_045, |
959 | .request_firmware = philips_tda1004x_request_firmware, | 816 | .i2c_gate = 0x4b, |
817 | .tuner_address = 0x61, | ||
818 | .tuner_config = 0, | ||
819 | .antenna_switch= 2, | ||
820 | .request_firmware = philips_tda1004x_request_firmware | ||
960 | }; | 821 | }; |
961 | 822 | ||
962 | static int asus_p7131_dual_tuner_init(struct dvb_frontend *fe) | ||
963 | { | ||
964 | struct saa7134_dev *dev = fe->dvb->priv; | ||
965 | static u8 data[] = { 0x3c, 0x33, 0x6a}; | ||
966 | struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; | ||
967 | |||
968 | if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) | ||
969 | return -EIO; | ||
970 | /* make sure the DVB-T antenna input is set */ | ||
971 | saa_setl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0200000); | ||
972 | return 0; | ||
973 | } | ||
974 | |||
975 | static int asus_p7131_dual_tuner_sleep(struct dvb_frontend *fe) | ||
976 | { | ||
977 | struct saa7134_dev *dev = fe->dvb->priv; | ||
978 | static u8 data[] = { 0x3c, 0x33, 0x68}; | ||
979 | struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; | ||
980 | |||
981 | i2c_transfer(&dev->i2c_adap, &msg, 1); | ||
982 | philips_tda827xa_tuner_sleep( 0x61, fe); | ||
983 | /* reset antenna inputs for analog usage */ | ||
984 | saa_clearl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0200000); | ||
985 | return 0; | ||
986 | } | ||
987 | |||
988 | /* ------------------------------------------------------------------ */ | ||
989 | |||
990 | static int lifeview_trio_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) | ||
991 | { | ||
992 | int ret; | ||
993 | |||
994 | ret = philips_tda827xa_pll_set(0x60, fe, params); | ||
995 | return ret; | ||
996 | } | ||
997 | |||
998 | static int lifeview_trio_tuner_sleep(struct dvb_frontend *fe) | ||
999 | { | ||
1000 | philips_tda827xa_tuner_sleep(0x60, fe); | ||
1001 | return 0; | ||
1002 | } | ||
1003 | |||
1004 | static struct tda1004x_config lifeview_trio_config = { | 823 | static struct tda1004x_config lifeview_trio_config = { |
1005 | .demod_address = 0x09, | 824 | .demod_address = 0x09, |
1006 | .invert = 1, | 825 | .invert = 1, |
1007 | .invert_oclk = 0, | 826 | .invert_oclk = 0, |
1008 | .xtal_freq = TDA10046_XTAL_16M, | 827 | .xtal_freq = TDA10046_XTAL_16M, |
1009 | .agc_config = TDA10046_AGC_TDA827X_GP00, | 828 | .agc_config = TDA10046_AGC_TDA827X, |
829 | .gpio_config = TDA10046_GP00_I, | ||
1010 | .if_freq = TDA10046_FREQ_045, | 830 | .if_freq = TDA10046_FREQ_045, |
1011 | .request_firmware = NULL, | 831 | .tuner_address = 0x60, |
832 | .request_firmware = philips_tda1004x_request_firmware | ||
1012 | }; | 833 | }; |
1013 | 834 | ||
1014 | /* ------------------------------------------------------------------ */ | 835 | static struct tda1004x_config tevion_dvbt220rf_config = { |
1015 | |||
1016 | static int ads_duo_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) | ||
1017 | { | ||
1018 | int ret; | ||
1019 | |||
1020 | ret = philips_tda827xa_pll_set(0x61, fe, params); | ||
1021 | return ret; | ||
1022 | } | ||
1023 | |||
1024 | static int ads_duo_tuner_init(struct dvb_frontend *fe) | ||
1025 | { | ||
1026 | struct saa7134_dev *dev = fe->dvb->priv; | ||
1027 | /* route TDA8275a AGC input to the channel decoder */ | ||
1028 | saa_writeb(SAA7134_GPIO_GPSTATUS2, 0x60); | ||
1029 | return 0; | ||
1030 | } | ||
1031 | |||
1032 | static int ads_duo_tuner_sleep(struct dvb_frontend *fe) | ||
1033 | { | ||
1034 | struct saa7134_dev *dev = fe->dvb->priv; | ||
1035 | /* route TDA8275a AGC input to the analog IF chip*/ | ||
1036 | saa_writeb(SAA7134_GPIO_GPSTATUS2, 0x20); | ||
1037 | philips_tda827xa_tuner_sleep( 0x61, fe); | ||
1038 | return 0; | ||
1039 | } | ||
1040 | |||
1041 | static struct tda1004x_config ads_tech_duo_config = { | ||
1042 | .demod_address = 0x08, | 836 | .demod_address = 0x08, |
1043 | .invert = 1, | 837 | .invert = 1, |
1044 | .invert_oclk = 0, | 838 | .invert_oclk = 0, |
1045 | .xtal_freq = TDA10046_XTAL_16M, | 839 | .xtal_freq = TDA10046_XTAL_16M, |
1046 | .agc_config = TDA10046_AGC_TDA827X_GP00, | 840 | .agc_config = TDA10046_AGC_TDA827X, |
841 | .gpio_config = TDA10046_GP11_I, | ||
1047 | .if_freq = TDA10046_FREQ_045, | 842 | .if_freq = TDA10046_FREQ_045, |
1048 | .request_firmware = NULL, | 843 | .tuner_address = 0x60, |
844 | .request_firmware = philips_tda1004x_request_firmware | ||
1049 | }; | 845 | }; |
1050 | 846 | ||
1051 | /* ------------------------------------------------------------------ */ | 847 | static struct tda1004x_config md8800_dvbt_config = { |
1052 | 848 | .demod_address = 0x08, | |
1053 | static int tevion_dvb220rf_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) | 849 | .invert = 1, |
1054 | { | 850 | .invert_oclk = 0, |
1055 | int ret; | 851 | .xtal_freq = TDA10046_XTAL_16M, |
1056 | ret = philips_tda827xa_pll_set(0x60, fe, params); | 852 | .agc_config = TDA10046_AGC_TDA827X, |
1057 | return ret; | 853 | .gpio_config = TDA10046_GP01_I, |
1058 | } | 854 | .if_freq = TDA10046_FREQ_045, |
1059 | 855 | .i2c_gate = 0x4b, | |
1060 | static int tevion_dvb220rf_tuner_sleep(struct dvb_frontend *fe) | 856 | .tuner_address = 0x60, |
1061 | { | 857 | .tuner_config = 0, |
1062 | philips_tda827xa_tuner_sleep( 0x61, fe); | 858 | .request_firmware = philips_tda1004x_request_firmware |
1063 | return 0; | 859 | }; |
1064 | } | ||
1065 | 860 | ||
1066 | static struct tda1004x_config tevion_dvbt220rf_config = { | 861 | static struct tda1004x_config asus_p7131_4871_config = { |
1067 | .demod_address = 0x08, | 862 | .demod_address = 0x08, |
1068 | .invert = 1, | 863 | .invert = 1, |
1069 | .invert_oclk = 0, | 864 | .invert_oclk = 0, |
1070 | .xtal_freq = TDA10046_XTAL_16M, | 865 | .xtal_freq = TDA10046_XTAL_16M, |
1071 | .agc_config = TDA10046_AGC_TDA827X_GP11, | 866 | .agc_config = TDA10046_AGC_TDA827X, |
867 | .gpio_config = TDA10046_GP01_I, | ||
1072 | .if_freq = TDA10046_FREQ_045, | 868 | .if_freq = TDA10046_FREQ_045, |
1073 | .request_firmware = NULL, | 869 | .i2c_gate = 0x4b, |
870 | .tuner_address = 0x61, | ||
871 | .tuner_config = 2, | ||
872 | .antenna_switch= 2, | ||
873 | .request_firmware = philips_tda1004x_request_firmware | ||
1074 | }; | 874 | }; |
1075 | 875 | ||
1076 | /* ------------------------------------------------------------------ */ | 876 | static struct tda1004x_config asus_p7131_hybrid_lna_config = { |
877 | .demod_address = 0x08, | ||
878 | .invert = 1, | ||
879 | .invert_oclk = 0, | ||
880 | .xtal_freq = TDA10046_XTAL_16M, | ||
881 | .agc_config = TDA10046_AGC_TDA827X, | ||
882 | .gpio_config = TDA10046_GP11_I, | ||
883 | .if_freq = TDA10046_FREQ_045, | ||
884 | .i2c_gate = 0x4b, | ||
885 | .tuner_address = 0x61, | ||
886 | .tuner_config = 2, | ||
887 | .antenna_switch= 2, | ||
888 | .request_firmware = philips_tda1004x_request_firmware | ||
889 | }; | ||
890 | /* ------------------------------------------------------------------ | ||
891 | * special case: this card uses saa713x GPIO22 for the mode switch | ||
892 | */ | ||
1077 | 893 | ||
1078 | static int md8800_dvbt_analog_mode(struct dvb_frontend *fe) | 894 | static int ads_duo_tuner_init(struct dvb_frontend *fe) |
1079 | { | 895 | { |
1080 | struct saa7134_dev *dev = fe->dvb->priv; | 896 | struct saa7134_dev *dev = fe->dvb->priv; |
1081 | static u8 data[] = { 0x3c, 0x33, 0x68}; | 897 | philips_tda827x_tuner_init(fe); |
1082 | struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; | 898 | /* route TDA8275a AGC input to the channel decoder */ |
1083 | 899 | saa7134_set_gpio(dev, 22, 1); | |
1084 | i2c_transfer(&dev->i2c_adap, &msg, 1); | ||
1085 | philips_tda827xa_tuner_sleep( 0x61, fe); | ||
1086 | return 0; | 900 | return 0; |
1087 | } | 901 | } |
1088 | 902 | ||
1089 | static int md8800_dvbt_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) | 903 | static int ads_duo_tuner_sleep(struct dvb_frontend *fe) |
1090 | { | 904 | { |
1091 | int ret; | ||
1092 | struct saa7134_dev *dev = fe->dvb->priv; | 905 | struct saa7134_dev *dev = fe->dvb->priv; |
1093 | static u8 tda8290_close[] = { 0x21, 0xc0}; | 906 | /* route TDA8275a AGC input to the analog IF chip*/ |
1094 | static u8 tda8290_open[] = { 0x21, 0x80}; | 907 | saa7134_set_gpio(dev, 22, 0); |
1095 | struct i2c_msg tda8290_msg = {.addr = 0x4b,.flags = 0, .len = 2}; | 908 | philips_tda827x_tuner_sleep(fe); |
1096 | /* close tda8290 i2c bridge */ | 909 | return 0; |
1097 | tda8290_msg.buf = tda8290_close; | ||
1098 | ret = i2c_transfer(&dev->i2c_adap, &tda8290_msg, 1); | ||
1099 | if (ret != 1) | ||
1100 | return -EIO; | ||
1101 | msleep(20); | ||
1102 | ret = philips_tda827xa_pll_set(0x60, fe, params); | ||
1103 | if (ret != 0) | ||
1104 | return ret; | ||
1105 | /* open tda8290 i2c bridge */ | ||
1106 | tda8290_msg.buf = tda8290_open; | ||
1107 | i2c_transfer(&dev->i2c_adap, &tda8290_msg, 1); | ||
1108 | return ret; | ||
1109 | } | 910 | } |
1110 | 911 | ||
1111 | static struct tda1004x_config md8800_dvbt_config = { | 912 | static struct tda827x_config ads_duo_cfg = { |
913 | .lna_gain = philips_tda827x_lna_gain, | ||
914 | .init = ads_duo_tuner_init, | ||
915 | .sleep = ads_duo_tuner_sleep | ||
916 | }; | ||
917 | |||
918 | static struct tda1004x_config ads_tech_duo_config = { | ||
1112 | .demod_address = 0x08, | 919 | .demod_address = 0x08, |
1113 | .invert = 1, | 920 | .invert = 1, |
1114 | .invert_oclk = 0, | 921 | .invert_oclk = 0, |
1115 | .xtal_freq = TDA10046_XTAL_16M, | 922 | .xtal_freq = TDA10046_XTAL_16M, |
1116 | .agc_config = TDA10046_AGC_TDA827X_GP11, | 923 | .agc_config = TDA10046_AGC_TDA827X, |
924 | .gpio_config = TDA10046_GP00_I, | ||
1117 | .if_freq = TDA10046_FREQ_045, | 925 | .if_freq = TDA10046_FREQ_045, |
1118 | .request_firmware = NULL, | 926 | .tuner_address = 0x61, |
927 | .request_firmware = philips_tda1004x_request_firmware | ||
1119 | }; | 928 | }; |
1120 | 929 | ||
930 | /* ================================================================== | ||
931 | * tda10086 based DVB-S cards, helper functions | ||
932 | */ | ||
933 | |||
1121 | static struct tda10086_config flydvbs = { | 934 | static struct tda10086_config flydvbs = { |
1122 | .demod_address = 0x0e, | 935 | .demod_address = 0x0e, |
1123 | .invert = 0, | 936 | .invert = 0, |
1124 | }; | 937 | }; |
1125 | 938 | ||
1126 | /* ------------------------------------------------------------------ */ | 939 | /* ================================================================== |
940 | * nxt200x based ATSC cards, helper functions | ||
941 | */ | ||
1127 | 942 | ||
1128 | static struct nxt200x_config avertvhda180 = { | 943 | static struct nxt200x_config avertvhda180 = { |
1129 | .demod_address = 0x0a, | 944 | .demod_address = 0x0a, |
@@ -1143,10 +958,13 @@ static struct nxt200x_config kworldatsc110 = { | |||
1143 | .set_pll_input = nxt200x_set_pll_input, | 958 | .set_pll_input = nxt200x_set_pll_input, |
1144 | }; | 959 | }; |
1145 | 960 | ||
1146 | /* ------------------------------------------------------------------ */ | 961 | /* ================================================================== |
962 | * Core code | ||
963 | */ | ||
1147 | 964 | ||
1148 | static int dvb_init(struct saa7134_dev *dev) | 965 | static int dvb_init(struct saa7134_dev *dev) |
1149 | { | 966 | { |
967 | int ret; | ||
1150 | /* init struct videobuf_dvb */ | 968 | /* init struct videobuf_dvb */ |
1151 | dev->ts.nr_bufs = 32; | 969 | dev->ts.nr_bufs = 32; |
1152 | dev->ts.nr_packets = 32*4; | 970 | dev->ts.nr_packets = 32*4; |
@@ -1160,7 +978,7 @@ static int dvb_init(struct saa7134_dev *dev) | |||
1160 | 978 | ||
1161 | switch (dev->board) { | 979 | switch (dev->board) { |
1162 | case SAA7134_BOARD_PINNACLE_300I_DVBT_PAL: | 980 | case SAA7134_BOARD_PINNACLE_300I_DVBT_PAL: |
1163 | printk("%s: pinnacle 300i dvb setup\n",dev->name); | 981 | dprintk("pinnacle 300i dvb setup\n"); |
1164 | dev->dvb.frontend = dvb_attach(mt352_attach, &pinnacle_300i, | 982 | dev->dvb.frontend = dvb_attach(mt352_attach, &pinnacle_300i, |
1165 | &dev->i2c_adap); | 983 | &dev->i2c_adap); |
1166 | if (dev->dvb.frontend) { | 984 | if (dev->dvb.frontend) { |
@@ -1169,7 +987,7 @@ static int dvb_init(struct saa7134_dev *dev) | |||
1169 | break; | 987 | break; |
1170 | case SAA7134_BOARD_AVERMEDIA_777: | 988 | case SAA7134_BOARD_AVERMEDIA_777: |
1171 | case SAA7134_BOARD_AVERMEDIA_A16AR: | 989 | case SAA7134_BOARD_AVERMEDIA_A16AR: |
1172 | printk("%s: avertv 777 dvb setup\n",dev->name); | 990 | dprintk("avertv 777 dvb setup\n"); |
1173 | dev->dvb.frontend = dvb_attach(mt352_attach, &avermedia_777, | 991 | dev->dvb.frontend = dvb_attach(mt352_attach, &avermedia_777, |
1174 | &dev->i2c_adap); | 992 | &dev->i2c_adap); |
1175 | if (dev->dvb.frontend) { | 993 | if (dev->dvb.frontend) { |
@@ -1191,42 +1009,15 @@ static int dvb_init(struct saa7134_dev *dev) | |||
1191 | &philips_tu1216_60_config, | 1009 | &philips_tu1216_60_config, |
1192 | &dev->i2c_adap); | 1010 | &dev->i2c_adap); |
1193 | if (dev->dvb.frontend) { | 1011 | if (dev->dvb.frontend) { |
1194 | dev->dvb.frontend->ops.tuner_ops.init = philips_tu1216_tuner_60_init; | 1012 | dev->dvb.frontend->ops.tuner_ops.init = philips_tu1216_init; |
1195 | dev->dvb.frontend->ops.tuner_ops.set_params = philips_tu1216_tuner_60_set_params; | 1013 | dev->dvb.frontend->ops.tuner_ops.set_params = philips_tda6651_pll_set; |
1196 | } | 1014 | } |
1197 | break; | 1015 | break; |
1198 | case SAA7134_BOARD_FLYDVBTDUO: | 1016 | case SAA7134_BOARD_FLYDVBTDUO: |
1199 | dev->dvb.frontend = dvb_attach(tda10046_attach, | ||
1200 | &tda827x_lifeview_config, | ||
1201 | &dev->i2c_adap); | ||
1202 | if (dev->dvb.frontend) { | ||
1203 | dev->dvb.frontend->ops.tuner_ops.init = philips_tda827x_tuner_init; | ||
1204 | dev->dvb.frontend->ops.tuner_ops.sleep = philips_tda827x_tuner_sleep; | ||
1205 | dev->dvb.frontend->ops.tuner_ops.set_params = philips_tda827x_tuner_set_params; | ||
1206 | } | ||
1207 | break; | ||
1208 | case SAA7134_BOARD_FLYDVBT_DUO_CARDBUS: | 1017 | case SAA7134_BOARD_FLYDVBT_DUO_CARDBUS: |
1209 | dev->dvb.frontend = dvb_attach(tda10046_attach, | 1018 | configure_tda827x_fe(dev, &tda827x_lifeview_config); |
1210 | &tda827x_lifeview_config, | ||
1211 | &dev->i2c_adap); | ||
1212 | if (dev->dvb.frontend) { | ||
1213 | dev->dvb.frontend->ops.tuner_ops.init = philips_tda827x_tuner_init; | ||
1214 | dev->dvb.frontend->ops.tuner_ops.sleep = philips_tda827x_tuner_sleep; | ||
1215 | dev->dvb.frontend->ops.tuner_ops.set_params = philips_tda827x_tuner_set_params; | ||
1216 | } | ||
1217 | break; | 1019 | break; |
1218 | case SAA7134_BOARD_PHILIPS_EUROPA: | 1020 | case SAA7134_BOARD_PHILIPS_EUROPA: |
1219 | dev->dvb.frontend = dvb_attach(tda10046_attach, | ||
1220 | &philips_europa_config, | ||
1221 | &dev->i2c_adap); | ||
1222 | if (dev->dvb.frontend) { | ||
1223 | dev->original_demod_sleep = dev->dvb.frontend->ops.sleep; | ||
1224 | dev->dvb.frontend->ops.sleep = philips_europa_demod_sleep; | ||
1225 | dev->dvb.frontend->ops.tuner_ops.init = philips_europa_tuner_init; | ||
1226 | dev->dvb.frontend->ops.tuner_ops.sleep = philips_europa_tuner_sleep; | ||
1227 | dev->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params; | ||
1228 | } | ||
1229 | break; | ||
1230 | case SAA7134_BOARD_VIDEOMATE_DVBT_300: | 1021 | case SAA7134_BOARD_VIDEOMATE_DVBT_300: |
1231 | dev->dvb.frontend = dvb_attach(tda10046_attach, | 1022 | dev->dvb.frontend = dvb_attach(tda10046_attach, |
1232 | &philips_europa_config, | 1023 | &philips_europa_config, |
@@ -1244,125 +1035,61 @@ static int dvb_init(struct saa7134_dev *dev) | |||
1244 | &philips_tu1216_61_config, | 1035 | &philips_tu1216_61_config, |
1245 | &dev->i2c_adap); | 1036 | &dev->i2c_adap); |
1246 | if (dev->dvb.frontend) { | 1037 | if (dev->dvb.frontend) { |
1247 | dev->dvb.frontend->ops.tuner_ops.init = philips_tu1216_tuner_61_init; | 1038 | dev->dvb.frontend->ops.tuner_ops.init = philips_tu1216_init; |
1248 | dev->dvb.frontend->ops.tuner_ops.set_params = philips_tu1216_tuner_61_set_params; | 1039 | dev->dvb.frontend->ops.tuner_ops.set_params = philips_tda6651_pll_set; |
1249 | } | 1040 | } |
1250 | break; | 1041 | break; |
1251 | case SAA7134_BOARD_PHILIPS_TIGER: | 1042 | case SAA7134_BOARD_PHILIPS_TIGER: |
1252 | dev->dvb.frontend = dvb_attach(tda10046_attach, | 1043 | configure_tda827x_fe(dev, &philips_tiger_config); |
1253 | &philips_tiger_config, | ||
1254 | &dev->i2c_adap); | ||
1255 | if (dev->dvb.frontend) { | ||
1256 | dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl; | ||
1257 | dev->dvb.frontend->ops.tuner_ops.init = philips_tiger_tuner_init; | ||
1258 | dev->dvb.frontend->ops.tuner_ops.sleep = philips_tiger_tuner_sleep; | ||
1259 | dev->dvb.frontend->ops.tuner_ops.set_params = philips_tiger_tuner_set_params; | ||
1260 | } | ||
1261 | break; | 1044 | break; |
1262 | case SAA7134_BOARD_PINNACLE_PCTV_310i: | 1045 | case SAA7134_BOARD_PINNACLE_PCTV_310i: |
1263 | dev->dvb.frontend = dvb_attach(tda10046_attach, | 1046 | configure_tda827x_fe(dev, &pinnacle_pctv_310i_config); |
1264 | &pinnacle_pctv_310i_config, | ||
1265 | &dev->i2c_adap); | ||
1266 | if (dev->dvb.frontend) { | ||
1267 | dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl; | ||
1268 | dev->dvb.frontend->ops.tuner_ops.init = philips_tiger_tuner_init; | ||
1269 | dev->dvb.frontend->ops.tuner_ops.sleep = philips_tiger_tuner_sleep; | ||
1270 | dev->dvb.frontend->ops.tuner_ops.set_params = philips_tiger_tuner_set_params; | ||
1271 | } | ||
1272 | break; | 1047 | break; |
1273 | case SAA7134_BOARD_HAUPPAUGE_HVR1110: | 1048 | case SAA7134_BOARD_HAUPPAUGE_HVR1110: |
1274 | dev->dvb.frontend = dvb_attach(tda10046_attach, | 1049 | configure_tda827x_fe(dev, &hauppauge_hvr_1110_config); |
1275 | &hauppauge_hvr_1110_config, | ||
1276 | &dev->i2c_adap); | ||
1277 | if (dev->dvb.frontend) { | ||
1278 | dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl; | ||
1279 | dev->dvb.frontend->ops.tuner_ops.init = philips_tiger_tuner_init; | ||
1280 | dev->dvb.frontend->ops.tuner_ops.sleep = philips_tiger_tuner_sleep; | ||
1281 | dev->dvb.frontend->ops.tuner_ops.set_params = philips_tiger_tuner_set_params; | ||
1282 | } | ||
1283 | break; | 1050 | break; |
1284 | case SAA7134_BOARD_ASUSTeK_P7131_DUAL: | 1051 | case SAA7134_BOARD_ASUSTeK_P7131_DUAL: |
1285 | dev->dvb.frontend = dvb_attach(tda10046_attach, | 1052 | configure_tda827x_fe(dev, &asus_p7131_dual_config); |
1286 | &asus_p7131_dual_config, | ||
1287 | &dev->i2c_adap); | ||
1288 | if (dev->dvb.frontend) { | ||
1289 | dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl; | ||
1290 | dev->dvb.frontend->ops.tuner_ops.init = asus_p7131_dual_tuner_init; | ||
1291 | dev->dvb.frontend->ops.tuner_ops.sleep = asus_p7131_dual_tuner_sleep; | ||
1292 | dev->dvb.frontend->ops.tuner_ops.set_params = philips_tiger_tuner_set_params; | ||
1293 | } | ||
1294 | break; | 1053 | break; |
1295 | case SAA7134_BOARD_FLYDVBT_LR301: | 1054 | case SAA7134_BOARD_FLYDVBT_LR301: |
1296 | dev->dvb.frontend = dvb_attach(tda10046_attach, | 1055 | configure_tda827x_fe(dev, &tda827x_lifeview_config); |
1297 | &tda827x_lifeview_config, | ||
1298 | &dev->i2c_adap); | ||
1299 | if (dev->dvb.frontend) { | ||
1300 | dev->dvb.frontend->ops.tuner_ops.init = philips_tda827x_tuner_init; | ||
1301 | dev->dvb.frontend->ops.tuner_ops.sleep = philips_tda827x_tuner_sleep; | ||
1302 | dev->dvb.frontend->ops.tuner_ops.set_params = philips_tda827x_tuner_set_params; | ||
1303 | } | ||
1304 | break; | 1056 | break; |
1305 | case SAA7134_BOARD_FLYDVB_TRIO: | 1057 | case SAA7134_BOARD_FLYDVB_TRIO: |
1306 | if(! use_frontend) { //terrestrial | 1058 | if(! use_frontend) { //terrestrial |
1307 | dev->dvb.frontend = dvb_attach(tda10046_attach, | 1059 | configure_tda827x_fe(dev, &lifeview_trio_config); |
1308 | &lifeview_trio_config, | ||
1309 | &dev->i2c_adap); | ||
1310 | if (dev->dvb.frontend) { | ||
1311 | dev->dvb.frontend->ops.tuner_ops.sleep = lifeview_trio_tuner_sleep; | ||
1312 | dev->dvb.frontend->ops.tuner_ops.set_params = | ||
1313 | lifeview_trio_tuner_set_params; | ||
1314 | } | ||
1315 | } else { //satellite | 1060 | } else { //satellite |
1316 | dev->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs, &dev->i2c_adap); | 1061 | dev->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs, &dev->i2c_adap); |
1317 | if (dev->dvb.frontend) { | 1062 | if (dev->dvb.frontend) { |
1318 | if (dvb_attach(tda826x_attach, dev->dvb.frontend, 0x63, | 1063 | if (dvb_attach(tda826x_attach, dev->dvb.frontend, 0x63, |
1319 | &dev->i2c_adap, 0) == NULL) { | 1064 | &dev->i2c_adap, 0) == NULL) { |
1320 | printk("%s: Lifeview Trio, No tda826x found!\n", __FUNCTION__); | 1065 | wprintk("%s: Lifeview Trio, No tda826x found!\n", __FUNCTION__); |
1321 | } | 1066 | } |
1322 | if (dvb_attach(isl6421_attach, dev->dvb.frontend, &dev->i2c_adap, | 1067 | if (dvb_attach(isl6421_attach, dev->dvb.frontend, &dev->i2c_adap, |
1323 | 0x08, 0, 0) == NULL) { | 1068 | 0x08, 0, 0) == NULL) { |
1324 | printk("%s: Lifeview Trio, No ISL6421 found!\n", __FUNCTION__); | 1069 | wprintk("%s: Lifeview Trio, No ISL6421 found!\n", __FUNCTION__); |
1325 | } | 1070 | } |
1326 | } | 1071 | } |
1327 | } | 1072 | } |
1328 | break; | 1073 | break; |
1329 | case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331: | 1074 | case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331: |
1075 | case SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS: | ||
1330 | dev->dvb.frontend = dvb_attach(tda10046_attach, | 1076 | dev->dvb.frontend = dvb_attach(tda10046_attach, |
1331 | &ads_tech_duo_config, | 1077 | &ads_tech_duo_config, |
1332 | &dev->i2c_adap); | 1078 | &dev->i2c_adap); |
1333 | if (dev->dvb.frontend) { | 1079 | if (dev->dvb.frontend) { |
1334 | dev->dvb.frontend->ops.tuner_ops.init = ads_duo_tuner_init; | 1080 | if (dvb_attach(tda827x_attach,dev->dvb.frontend, |
1335 | dev->dvb.frontend->ops.tuner_ops.sleep = ads_duo_tuner_sleep; | 1081 | ads_tech_duo_config.tuner_address, |
1336 | dev->dvb.frontend->ops.tuner_ops.set_params = ads_duo_tuner_set_params; | 1082 | &dev->i2c_adap,&ads_duo_cfg) == NULL) { |
1083 | wprintk("no tda827x tuner found at addr: %02x\n", | ||
1084 | ads_tech_duo_config.tuner_address); | ||
1085 | } | ||
1337 | } | 1086 | } |
1338 | break; | 1087 | break; |
1339 | case SAA7134_BOARD_TEVION_DVBT_220RF: | 1088 | case SAA7134_BOARD_TEVION_DVBT_220RF: |
1340 | dev->dvb.frontend = dvb_attach(tda10046_attach, | 1089 | configure_tda827x_fe(dev, &tevion_dvbt220rf_config); |
1341 | &tevion_dvbt220rf_config, | ||
1342 | &dev->i2c_adap); | ||
1343 | if (dev->dvb.frontend) { | ||
1344 | dev->dvb.frontend->ops.tuner_ops.sleep = tevion_dvb220rf_tuner_sleep; | ||
1345 | dev->dvb.frontend->ops.tuner_ops.set_params = tevion_dvb220rf_tuner_set_params; | ||
1346 | } | ||
1347 | break; | ||
1348 | case SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS: | ||
1349 | dev->dvb.frontend = dvb_attach(tda10046_attach, | ||
1350 | &ads_tech_duo_config, | ||
1351 | &dev->i2c_adap); | ||
1352 | if (dev->dvb.frontend) { | ||
1353 | dev->dvb.frontend->ops.tuner_ops.init = ads_duo_tuner_init; | ||
1354 | dev->dvb.frontend->ops.tuner_ops.sleep = ads_duo_tuner_sleep; | ||
1355 | dev->dvb.frontend->ops.tuner_ops.set_params = ads_duo_tuner_set_params; | ||
1356 | } | ||
1357 | break; | 1090 | break; |
1358 | case SAA7134_BOARD_MEDION_MD8800_QUADRO: | 1091 | case SAA7134_BOARD_MEDION_MD8800_QUADRO: |
1359 | dev->dvb.frontend = tda10046_attach(&md8800_dvbt_config, | 1092 | configure_tda827x_fe(dev, &md8800_dvbt_config); |
1360 | &dev->i2c_adap); | ||
1361 | if (dev->dvb.frontend) { | ||
1362 | dev->dvb.frontend->ops.tuner_ops.init = philips_tiger_tuner_init; | ||
1363 | dev->dvb.frontend->ops.tuner_ops.sleep = md8800_dvbt_analog_mode; | ||
1364 | dev->dvb.frontend->ops.tuner_ops.set_params = md8800_dvbt_pll_set; | ||
1365 | } | ||
1366 | break; | 1093 | break; |
1367 | case SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180: | 1094 | case SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180: |
1368 | dev->dvb.frontend = dvb_attach(nxt200x_attach, &avertvhda180, | 1095 | dev->dvb.frontend = dvb_attach(nxt200x_attach, &avertvhda180, |
@@ -1386,11 +1113,11 @@ static int dvb_init(struct saa7134_dev *dev) | |||
1386 | if (dev->dvb.frontend) { | 1113 | if (dev->dvb.frontend) { |
1387 | if (dvb_attach(tda826x_attach, dev->dvb.frontend, 0x60, | 1114 | if (dvb_attach(tda826x_attach, dev->dvb.frontend, 0x60, |
1388 | &dev->i2c_adap, 0) == NULL) { | 1115 | &dev->i2c_adap, 0) == NULL) { |
1389 | printk("%s: No tda826x found!\n", __FUNCTION__); | 1116 | wprintk("%s: No tda826x found!\n", __FUNCTION__); |
1390 | } | 1117 | } |
1391 | if (dvb_attach(isl6421_attach, dev->dvb.frontend, | 1118 | if (dvb_attach(isl6421_attach, dev->dvb.frontend, |
1392 | &dev->i2c_adap, 0x08, 0, 0) == NULL) { | 1119 | &dev->i2c_adap, 0x08, 0, 0) == NULL) { |
1393 | printk("%s: No ISL6421 found!\n", __FUNCTION__); | 1120 | wprintk("%s: No ISL6421 found!\n", __FUNCTION__); |
1394 | } | 1121 | } |
1395 | } | 1122 | } |
1396 | break; | 1123 | break; |
@@ -1415,41 +1142,45 @@ static int dvb_init(struct saa7134_dev *dev) | |||
1415 | } | 1142 | } |
1416 | break; | 1143 | break; |
1417 | case SAA7134_BOARD_CINERGY_HT_PCMCIA: | 1144 | case SAA7134_BOARD_CINERGY_HT_PCMCIA: |
1418 | dev->dvb.frontend = dvb_attach(tda10046_attach, | 1145 | configure_tda827x_fe(dev, &cinergy_ht_config); |
1419 | &cinergy_ht_config, | ||
1420 | &dev->i2c_adap); | ||
1421 | if (dev->dvb.frontend) { | ||
1422 | dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl; | ||
1423 | dev->dvb.frontend->ops.tuner_ops.init = cinergy_ht_tuner_init; | ||
1424 | dev->dvb.frontend->ops.tuner_ops.sleep = cinergy_ht_tuner_sleep; | ||
1425 | dev->dvb.frontend->ops.tuner_ops.set_params = philips_tiger_tuner_set_params; | ||
1426 | |||
1427 | } | ||
1428 | break; | 1146 | break; |
1429 | case SAA7134_BOARD_CINERGY_HT_PCI: | 1147 | case SAA7134_BOARD_CINERGY_HT_PCI: |
1430 | dev->dvb.frontend = dvb_attach(tda10046_attach, | 1148 | configure_tda827x_fe(dev, &cinergy_ht_pci_config); |
1431 | &cinergy_ht_config, | 1149 | break; |
1432 | &dev->i2c_adap); | 1150 | case SAA7134_BOARD_PHILIPS_TIGER_S: |
1433 | if (dev->dvb.frontend) { | 1151 | configure_tda827x_fe(dev, &philips_tiger_s_config); |
1434 | dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl; | 1152 | break; |
1435 | dev->dvb.frontend->ops.tuner_ops.init = cinergy_ht_tuner_init; | 1153 | case SAA7134_BOARD_ASUS_P7131_4871: |
1436 | dev->dvb.frontend->ops.tuner_ops.sleep = cinergy_ht_tuner_sleep; | 1154 | configure_tda827x_fe(dev, &asus_p7131_4871_config); |
1437 | dev->dvb.frontend->ops.tuner_ops.set_params = md8800_dvbt_pll_set; | 1155 | break; |
1438 | 1156 | case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA: | |
1439 | } | 1157 | configure_tda827x_fe(dev, &asus_p7131_hybrid_lna_config); |
1440 | break; | 1158 | break; |
1441 | default: | 1159 | default: |
1442 | printk("%s: Huh? unknown DVB card?\n",dev->name); | 1160 | wprintk("Huh? unknown DVB card?\n"); |
1443 | break; | 1161 | break; |
1444 | } | 1162 | } |
1445 | 1163 | ||
1446 | if (NULL == dev->dvb.frontend) { | 1164 | if (NULL == dev->dvb.frontend) { |
1447 | printk("%s: frontend initialization failed\n",dev->name); | 1165 | printk(KERN_ERR "%s/dvb: frontend initialization failed\n", dev->name); |
1448 | return -1; | 1166 | return -1; |
1449 | } | 1167 | } |
1450 | 1168 | ||
1451 | /* register everything else */ | 1169 | /* register everything else */ |
1452 | return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev, &dev->pci->dev); | 1170 | ret = videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev, &dev->pci->dev); |
1171 | |||
1172 | /* this sequence is necessary to make the tda1004x load its firmware | ||
1173 | * and to enter analog mode of hybrid boards | ||
1174 | */ | ||
1175 | if (!ret) { | ||
1176 | if (dev->dvb.frontend->ops.init) | ||
1177 | dev->dvb.frontend->ops.init(dev->dvb.frontend); | ||
1178 | if (dev->dvb.frontend->ops.sleep) | ||
1179 | dev->dvb.frontend->ops.sleep(dev->dvb.frontend); | ||
1180 | if (dev->dvb.frontend->ops.tuner_ops.sleep) | ||
1181 | dev->dvb.frontend->ops.tuner_ops.sleep(dev->dvb.frontend); | ||
1182 | } | ||
1183 | return ret; | ||
1453 | } | 1184 | } |
1454 | 1185 | ||
1455 | static int dvb_fini(struct saa7134_dev *dev) | 1186 | static int dvb_fini(struct saa7134_dev *dev) |
diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c index cce8da6a4f94..1cb8c709ca90 100644 --- a/drivers/media/video/saa7134/saa7134-i2c.c +++ b/drivers/media/video/saa7134/saa7134-i2c.c | |||
@@ -370,6 +370,8 @@ static int attach_inform(struct i2c_client *client) | |||
370 | 370 | ||
371 | tun_setup.type = tuner; | 371 | tun_setup.type = tuner; |
372 | tun_setup.addr = saa7134_boards[dev->board].tuner_addr; | 372 | tun_setup.addr = saa7134_boards[dev->board].tuner_addr; |
373 | tun_setup.config = saa7134_boards[dev->board].tuner_config; | ||
374 | tun_setup.tuner_callback = saa7134_tuner_callback; | ||
373 | 375 | ||
374 | if ((tun_setup.addr == ADDR_UNSET)||(tun_setup.addr == client->addr)) { | 376 | if ((tun_setup.addr == ADDR_UNSET)||(tun_setup.addr == client->addr)) { |
375 | 377 | ||
@@ -445,7 +447,7 @@ static void do_i2c_scan(char *name, struct i2c_client *c) | |||
445 | unsigned char buf; | 447 | unsigned char buf; |
446 | int i,rc; | 448 | int i,rc; |
447 | 449 | ||
448 | for (i = 0; i < 128; i++) { | 450 | for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) { |
449 | c->addr = i; | 451 | c->addr = i; |
450 | rc = i2c_master_recv(c,&buf,0); | 452 | rc = i2c_master_recv(c,&buf,0); |
451 | if (rc < 0) | 453 | if (rc < 0) |
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index 46c583f1e788..c0de37e3f5c6 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c | |||
@@ -321,6 +321,7 @@ int saa7134_input_init1(struct saa7134_dev *dev) | |||
321 | mask_keydown = 0x0040000; | 321 | mask_keydown = 0x0040000; |
322 | break; | 322 | break; |
323 | case SAA7134_BOARD_ASUSTeK_P7131_DUAL: | 323 | case SAA7134_BOARD_ASUSTeK_P7131_DUAL: |
324 | case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA: | ||
324 | ir_codes = ir_codes_asus_pc39; | 325 | ir_codes = ir_codes_asus_pc39; |
325 | mask_keydown = 0x0040000; | 326 | mask_keydown = 0x0040000; |
326 | rc5_gpio = 1; | 327 | rc5_gpio = 1; |
diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index f2cb63053041..9985ded20950 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/moduleparam.h> | 26 | #include <linux/moduleparam.h> |
27 | #include <linux/kernel.h> | 27 | #include <linux/kernel.h> |
28 | #include <linux/slab.h> | 28 | #include <linux/slab.h> |
29 | #include <linux/sort.h> | ||
29 | 30 | ||
30 | #include "saa7134-reg.h" | 31 | #include "saa7134-reg.h" |
31 | #include "saa7134.h" | 32 | #include "saa7134.h" |
@@ -516,14 +517,12 @@ static int res_get(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int | |||
516 | return 1; | 517 | return 1; |
517 | } | 518 | } |
518 | 519 | ||
519 | static | 520 | static int res_check(struct saa7134_fh *fh, unsigned int bit) |
520 | int res_check(struct saa7134_fh *fh, unsigned int bit) | ||
521 | { | 521 | { |
522 | return (fh->resources & bit); | 522 | return (fh->resources & bit); |
523 | } | 523 | } |
524 | 524 | ||
525 | static | 525 | static int res_locked(struct saa7134_dev *dev, unsigned int bit) |
526 | int res_locked(struct saa7134_dev *dev, unsigned int bit) | ||
527 | { | 526 | { |
528 | return (dev->resources & bit); | 527 | return (dev->resources & bit); |
529 | } | 528 | } |
@@ -603,7 +602,14 @@ static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm) | |||
603 | saa_writeb(SAA7134_RAW_DATA_GAIN, 0x40); | 602 | saa_writeb(SAA7134_RAW_DATA_GAIN, 0x40); |
604 | saa_writeb(SAA7134_RAW_DATA_OFFSET, 0x80); | 603 | saa_writeb(SAA7134_RAW_DATA_OFFSET, 0x80); |
605 | 604 | ||
606 | saa7134_i2c_call_clients(dev,VIDIOC_S_STD,&norm->id); | 605 | /* only tell the tuner if this is a tv input */ |
606 | if (card_in(dev,dev->ctl_input).tv) { | ||
607 | if ((card(dev).tuner_type == TUNER_PHILIPS_TDA8290) | ||
608 | && ((card(dev).tuner_config == 1) | ||
609 | || (card(dev).tuner_config == 2))) | ||
610 | saa7134_set_gpio(dev, 22, 5); | ||
611 | saa7134_i2c_call_clients(dev,VIDIOC_S_STD,&norm->id); | ||
612 | } | ||
607 | } | 613 | } |
608 | 614 | ||
609 | static void video_mux(struct saa7134_dev *dev, int input) | 615 | static void video_mux(struct saa7134_dev *dev, int input) |
@@ -732,25 +738,6 @@ struct cliplist { | |||
732 | __u8 disable; | 738 | __u8 disable; |
733 | }; | 739 | }; |
734 | 740 | ||
735 | static void sort_cliplist(struct cliplist *cl, int entries) | ||
736 | { | ||
737 | struct cliplist swap; | ||
738 | int i,j,n; | ||
739 | |||
740 | for (i = entries-2; i >= 0; i--) { | ||
741 | for (n = 0, j = 0; j <= i; j++) { | ||
742 | if (cl[j].position > cl[j+1].position) { | ||
743 | swap = cl[j]; | ||
744 | cl[j] = cl[j+1]; | ||
745 | cl[j+1] = swap; | ||
746 | n++; | ||
747 | } | ||
748 | } | ||
749 | if (0 == n) | ||
750 | break; | ||
751 | } | ||
752 | } | ||
753 | |||
754 | static void set_cliplist(struct saa7134_dev *dev, int reg, | 741 | static void set_cliplist(struct saa7134_dev *dev, int reg, |
755 | struct cliplist *cl, int entries, char *name) | 742 | struct cliplist *cl, int entries, char *name) |
756 | { | 743 | { |
@@ -784,15 +771,27 @@ static int clip_range(int val) | |||
784 | return val; | 771 | return val; |
785 | } | 772 | } |
786 | 773 | ||
774 | /* Sort into smallest position first order */ | ||
775 | static int cliplist_cmp(const void *a, const void *b) | ||
776 | { | ||
777 | const struct cliplist *cla = a; | ||
778 | const struct cliplist *clb = b; | ||
779 | if (cla->position < clb->position) | ||
780 | return -1; | ||
781 | if (cla->position > clb->position) | ||
782 | return 1; | ||
783 | return 0; | ||
784 | } | ||
785 | |||
787 | static int setup_clipping(struct saa7134_dev *dev, struct v4l2_clip *clips, | 786 | static int setup_clipping(struct saa7134_dev *dev, struct v4l2_clip *clips, |
788 | int nclips, int interlace) | 787 | int nclips, int interlace) |
789 | { | 788 | { |
790 | struct cliplist col[16], row[16]; | 789 | struct cliplist col[16], row[16]; |
791 | int cols, rows, i; | 790 | int cols = 0, rows = 0, i; |
792 | int div = interlace ? 2 : 1; | 791 | int div = interlace ? 2 : 1; |
793 | 792 | ||
794 | memset(col,0,sizeof(col)); cols = 0; | 793 | memset(col, 0, sizeof(col)); |
795 | memset(row,0,sizeof(row)); rows = 0; | 794 | memset(row, 0, sizeof(row)); |
796 | for (i = 0; i < nclips && i < 8; i++) { | 795 | for (i = 0; i < nclips && i < 8; i++) { |
797 | col[cols].position = clip_range(clips[i].c.left); | 796 | col[cols].position = clip_range(clips[i].c.left); |
798 | col[cols].enable = (1 << i); | 797 | col[cols].enable = (1 << i); |
@@ -808,8 +807,8 @@ static int setup_clipping(struct saa7134_dev *dev, struct v4l2_clip *clips, | |||
808 | row[rows].disable = (1 << i); | 807 | row[rows].disable = (1 << i); |
809 | rows++; | 808 | rows++; |
810 | } | 809 | } |
811 | sort_cliplist(col,cols); | 810 | sort(col, cols, sizeof col[0], cliplist_cmp, NULL); |
812 | sort_cliplist(row,rows); | 811 | sort(row, rows, sizeof row[0], cliplist_cmp, NULL); |
813 | set_cliplist(dev,0x380,col,cols,"cols"); | 812 | set_cliplist(dev,0x380,col,cols,"cols"); |
814 | set_cliplist(dev,0x384,row,rows,"rows"); | 813 | set_cliplist(dev,0x384,row,rows,"rows"); |
815 | return 0; | 814 | return 0; |
@@ -1261,19 +1260,14 @@ static struct videobuf_queue* saa7134_queue(struct saa7134_fh *fh) | |||
1261 | 1260 | ||
1262 | static int saa7134_resource(struct saa7134_fh *fh) | 1261 | static int saa7134_resource(struct saa7134_fh *fh) |
1263 | { | 1262 | { |
1264 | int res = 0; | 1263 | if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) |
1264 | return RESOURCE_VIDEO; | ||
1265 | 1265 | ||
1266 | switch (fh->type) { | 1266 | if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) |
1267 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | 1267 | return RESOURCE_VBI; |
1268 | res = RESOURCE_VIDEO; | 1268 | |
1269 | break; | 1269 | BUG(); |
1270 | case V4L2_BUF_TYPE_VBI_CAPTURE: | 1270 | return 0; |
1271 | res = RESOURCE_VBI; | ||
1272 | break; | ||
1273 | default: | ||
1274 | BUG(); | ||
1275 | } | ||
1276 | return res; | ||
1277 | } | 1271 | } |
1278 | 1272 | ||
1279 | static int video_open(struct inode *inode, struct file *file) | 1273 | static int video_open(struct inode *inode, struct file *file) |
@@ -1461,8 +1455,7 @@ static int video_release(struct inode *inode, struct file *file) | |||
1461 | return 0; | 1455 | return 0; |
1462 | } | 1456 | } |
1463 | 1457 | ||
1464 | static int | 1458 | static int video_mmap(struct file *file, struct vm_area_struct * vma) |
1465 | video_mmap(struct file *file, struct vm_area_struct * vma) | ||
1466 | { | 1459 | { |
1467 | struct saa7134_fh *fh = file->private_data; | 1460 | struct saa7134_fh *fh = file->private_data; |
1468 | 1461 | ||
@@ -2461,12 +2454,6 @@ int saa7134_video_init2(struct saa7134_dev *dev) | |||
2461 | return 0; | 2454 | return 0; |
2462 | } | 2455 | } |
2463 | 2456 | ||
2464 | int saa7134_video_fini(struct saa7134_dev *dev) | ||
2465 | { | ||
2466 | /* nothing */ | ||
2467 | return 0; | ||
2468 | } | ||
2469 | |||
2470 | void saa7134_irq_video_intl(struct saa7134_dev *dev) | 2457 | void saa7134_irq_video_intl(struct saa7134_dev *dev) |
2471 | { | 2458 | { |
2472 | static const char *st[] = { | 2459 | static const char *st[] = { |
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index b3e3957c89b5..62224cc958f1 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h | |||
@@ -231,6 +231,10 @@ struct saa7134_format { | |||
231 | #define SAA7134_BOARD_ENCORE_ENLTV 106 | 231 | #define SAA7134_BOARD_ENCORE_ENLTV 106 |
232 | #define SAA7134_BOARD_ENCORE_ENLTV_FM 107 | 232 | #define SAA7134_BOARD_ENCORE_ENLTV_FM 107 |
233 | #define SAA7134_BOARD_CINERGY_HT_PCI 108 | 233 | #define SAA7134_BOARD_CINERGY_HT_PCI 108 |
234 | #define SAA7134_BOARD_PHILIPS_TIGER_S 109 | ||
235 | #define SAA7134_BOARD_AVERMEDIA_M102 110 | ||
236 | #define SAA7134_BOARD_ASUS_P7131_4871 111 | ||
237 | #define SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA 112 | ||
234 | 238 | ||
235 | #define SAA7134_MAXBOARDS 8 | 239 | #define SAA7134_MAXBOARDS 8 |
236 | #define SAA7134_INPUT_MAX 8 | 240 | #define SAA7134_INPUT_MAX 8 |
@@ -280,6 +284,7 @@ struct saa7134_board { | |||
280 | unsigned char radio_addr; | 284 | unsigned char radio_addr; |
281 | 285 | ||
282 | unsigned int tda9887_conf; | 286 | unsigned int tda9887_conf; |
287 | unsigned int tuner_config; | ||
283 | 288 | ||
284 | /* peripheral I/O */ | 289 | /* peripheral I/O */ |
285 | enum saa7134_video_out video_out; | 290 | enum saa7134_video_out video_out; |
@@ -435,6 +440,8 @@ struct saa7134_dev { | |||
435 | #ifdef VIDIOC_G_PRIORITY | 440 | #ifdef VIDIOC_G_PRIORITY |
436 | struct v4l2_prio_state prio; | 441 | struct v4l2_prio_state prio; |
437 | #endif | 442 | #endif |
443 | /* workstruct for loading modules */ | ||
444 | struct work_struct request_module_wk; | ||
438 | 445 | ||
439 | /* insmod option/autodetected */ | 446 | /* insmod option/autodetected */ |
440 | int autodetected; | 447 | int autodetected; |
@@ -562,6 +569,8 @@ extern struct list_head saa7134_devlist; | |||
562 | extern int saa7134_no_overlay; | 569 | extern int saa7134_no_overlay; |
563 | 570 | ||
564 | void saa7134_track_gpio(struct saa7134_dev *dev, char *msg); | 571 | void saa7134_track_gpio(struct saa7134_dev *dev, char *msg); |
572 | void saa7134_set_gpio(struct saa7134_dev *dev, int bit_no, int value); | ||
573 | int saa7134_tuner_callback(void *ptr, int command, int arg); | ||
565 | 574 | ||
566 | #define SAA7134_PGTABLE_SIZE 4096 | 575 | #define SAA7134_PGTABLE_SIZE 4096 |
567 | 576 | ||
@@ -620,7 +629,6 @@ int saa7134_common_ioctl(struct saa7134_dev *dev, | |||
620 | 629 | ||
621 | int saa7134_video_init1(struct saa7134_dev *dev); | 630 | int saa7134_video_init1(struct saa7134_dev *dev); |
622 | int saa7134_video_init2(struct saa7134_dev *dev); | 631 | int saa7134_video_init2(struct saa7134_dev *dev); |
623 | int saa7134_video_fini(struct saa7134_dev *dev); | ||
624 | void saa7134_irq_video_intl(struct saa7134_dev *dev); | 632 | void saa7134_irq_video_intl(struct saa7134_dev *dev); |
625 | void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status); | 633 | void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status); |
626 | 634 | ||
diff --git a/drivers/media/video/se401.c b/drivers/media/video/se401.c index 038448f5a978..93fb04ed99a0 100644 --- a/drivers/media/video/se401.c +++ b/drivers/media/video/se401.c | |||
@@ -450,6 +450,13 @@ static int se401_start_stream(struct usb_se401 *se401) | |||
450 | } | 450 | } |
451 | for (i=0; i<SE401_NUMSBUF; i++) { | 451 | for (i=0; i<SE401_NUMSBUF; i++) { |
452 | se401->sbuf[i].data=kmalloc(SE401_PACKETSIZE, GFP_KERNEL); | 452 | se401->sbuf[i].data=kmalloc(SE401_PACKETSIZE, GFP_KERNEL); |
453 | if (!se401->sbuf[i].data) { | ||
454 | for(i = i - 1; i >= 0; i--) { | ||
455 | kfree(se401->sbuf[i].data); | ||
456 | se401->sbuf[i].data = NULL; | ||
457 | } | ||
458 | return -ENOMEM; | ||
459 | } | ||
453 | } | 460 | } |
454 | 461 | ||
455 | se401->bayeroffset=0; | 462 | se401->bayeroffset=0; |
@@ -458,13 +465,26 @@ static int se401_start_stream(struct usb_se401 *se401) | |||
458 | se401->scratch_overflow=0; | 465 | se401->scratch_overflow=0; |
459 | for (i=0; i<SE401_NUMSCRATCH; i++) { | 466 | for (i=0; i<SE401_NUMSCRATCH; i++) { |
460 | se401->scratch[i].data=kmalloc(SE401_PACKETSIZE, GFP_KERNEL); | 467 | se401->scratch[i].data=kmalloc(SE401_PACKETSIZE, GFP_KERNEL); |
468 | if (!se401->scratch[i].data) { | ||
469 | for(i = i - 1; i >= 0; i--) { | ||
470 | kfree(se401->scratch[i].data); | ||
471 | se401->scratch[i].data = NULL; | ||
472 | } | ||
473 | goto nomem_sbuf; | ||
474 | } | ||
461 | se401->scratch[i].state=BUFFER_UNUSED; | 475 | se401->scratch[i].state=BUFFER_UNUSED; |
462 | } | 476 | } |
463 | 477 | ||
464 | for (i=0; i<SE401_NUMSBUF; i++) { | 478 | for (i=0; i<SE401_NUMSBUF; i++) { |
465 | urb=usb_alloc_urb(0, GFP_KERNEL); | 479 | urb=usb_alloc_urb(0, GFP_KERNEL); |
466 | if(!urb) | 480 | if(!urb) { |
467 | return -ENOMEM; | 481 | for(i = i - 1; i >= 0; i--) { |
482 | usb_kill_urb(se401->urb[i]); | ||
483 | usb_free_urb(se401->urb[i]); | ||
484 | se401->urb[i] = NULL; | ||
485 | } | ||
486 | goto nomem_scratch; | ||
487 | } | ||
468 | 488 | ||
469 | usb_fill_bulk_urb(urb, se401->dev, | 489 | usb_fill_bulk_urb(urb, se401->dev, |
470 | usb_rcvbulkpipe(se401->dev, SE401_VIDEO_ENDPOINT), | 490 | usb_rcvbulkpipe(se401->dev, SE401_VIDEO_ENDPOINT), |
@@ -482,6 +502,18 @@ static int se401_start_stream(struct usb_se401 *se401) | |||
482 | se401->framecount=0; | 502 | se401->framecount=0; |
483 | 503 | ||
484 | return 0; | 504 | return 0; |
505 | |||
506 | nomem_scratch: | ||
507 | for (i=0; i<SE401_NUMSCRATCH; i++) { | ||
508 | kfree(se401->scratch[i].data); | ||
509 | se401->scratch[i].data = NULL; | ||
510 | } | ||
511 | nomem_sbuf: | ||
512 | for (i=0; i<SE401_NUMSBUF; i++) { | ||
513 | kfree(se401->sbuf[i].data); | ||
514 | se401->sbuf[i].data = NULL; | ||
515 | } | ||
516 | return -ENOMEM; | ||
485 | } | 517 | } |
486 | 518 | ||
487 | static int se401_stop_stream(struct usb_se401 *se401) | 519 | static int se401_stop_stream(struct usb_se401 *se401) |
diff --git a/drivers/media/video/sn9c102/Kconfig b/drivers/media/video/sn9c102/Kconfig index 1a7ccb666ab0..19204f5686e1 100644 --- a/drivers/media/video/sn9c102/Kconfig +++ b/drivers/media/video/sn9c102/Kconfig | |||
@@ -1,6 +1,6 @@ | |||
1 | config USB_SN9C102 | 1 | config USB_SN9C102 |
2 | tristate "USB SN9C1xx PC Camera Controller support" | 2 | tristate "USB SN9C1xx PC Camera Controller support" |
3 | depends on USB && VIDEO_V4L1 | 3 | depends on USB && VIDEO_V4L2 |
4 | ---help--- | 4 | ---help--- |
5 | Say Y here if you want support for cameras based on SONiX SN9C101, | 5 | Say Y here if you want support for cameras based on SONiX SN9C101, |
6 | SN9C102, SN9C103, SN9C105 and SN9C120 PC Camera Controllers. | 6 | SN9C102, SN9C103, SN9C105 and SN9C120 PC Camera Controllers. |
diff --git a/drivers/media/video/sn9c102/Makefile b/drivers/media/video/sn9c102/Makefile index 30e3dfe537fe..a56d16f69c71 100644 --- a/drivers/media/video/sn9c102/Makefile +++ b/drivers/media/video/sn9c102/Makefile | |||
@@ -1,7 +1,14 @@ | |||
1 | sn9c102-objs := sn9c102_core.o sn9c102_hv7131d.o sn9c102_mi0343.o \ | 1 | sn9c102-objs := sn9c102_core.o \ |
2 | sn9c102_ov7630.o sn9c102_ov7660.o sn9c102_pas106b.o \ | 2 | sn9c102_hv7131d.o \ |
3 | sn9c102_pas202bcb.o sn9c102_tas5110c1b.o \ | 3 | sn9c102_hv7131r.o \ |
4 | sn9c102_tas5130d1b.o | 4 | sn9c102_mi0343.o \ |
5 | sn9c102_mi0360.o \ | ||
6 | sn9c102_ov7630.o \ | ||
7 | sn9c102_ov7660.o \ | ||
8 | sn9c102_pas106b.o \ | ||
9 | sn9c102_pas202bcb.o \ | ||
10 | sn9c102_tas5110c1b.o \ | ||
11 | sn9c102_tas5110d.o \ | ||
12 | sn9c102_tas5130d1b.o | ||
5 | 13 | ||
6 | obj-$(CONFIG_USB_SN9C102) += sn9c102.o | 14 | obj-$(CONFIG_USB_SN9C102) += sn9c102.o |
7 | |||
diff --git a/drivers/media/video/sn9c102/sn9c102.h b/drivers/media/video/sn9c102/sn9c102.h index 5428f34e7c5b..680e74634527 100644 --- a/drivers/media/video/sn9c102/sn9c102.h +++ b/drivers/media/video/sn9c102/sn9c102.h | |||
@@ -78,8 +78,13 @@ enum sn9c102_stream_state { | |||
78 | 78 | ||
79 | typedef char sn9c102_sof_header_t[62]; | 79 | typedef char sn9c102_sof_header_t[62]; |
80 | 80 | ||
81 | struct sn9c102_sof_t { | ||
82 | sn9c102_sof_header_t header; | ||
83 | u16 bytesread; | ||
84 | }; | ||
85 | |||
81 | struct sn9c102_sysfs_attr { | 86 | struct sn9c102_sysfs_attr { |
82 | u8 reg, i2c_reg; | 87 | u16 reg, i2c_reg; |
83 | sn9c102_sof_header_t frame_header; | 88 | sn9c102_sof_header_t frame_header; |
84 | }; | 89 | }; |
85 | 90 | ||
@@ -112,7 +117,7 @@ struct sn9c102_device { | |||
112 | struct v4l2_jpegcompression compression; | 117 | struct v4l2_jpegcompression compression; |
113 | 118 | ||
114 | struct sn9c102_sysfs_attr sysfs; | 119 | struct sn9c102_sysfs_attr sysfs; |
115 | sn9c102_sof_header_t sof_header; | 120 | struct sn9c102_sof_t sof; |
116 | u16 reg[384]; | 121 | u16 reg[384]; |
117 | 122 | ||
118 | struct sn9c102_module_param module_param; | 123 | struct sn9c102_module_param module_param; |
@@ -182,8 +187,8 @@ do { \ | |||
182 | if ((level) == 1 || (level) == 2) \ | 187 | if ((level) == 1 || (level) == 2) \ |
183 | pr_info("sn9c102: " fmt "\n", ## args); \ | 188 | pr_info("sn9c102: " fmt "\n", ## args); \ |
184 | else if ((level) == 3) \ | 189 | else if ((level) == 3) \ |
185 | pr_debug("sn9c102: [%s:%d] " fmt "\n", __FUNCTION__, \ | 190 | pr_debug("sn9c102: [%s:%d] " fmt "\n", \ |
186 | __LINE__ , ## args); \ | 191 | __FUNCTION__, __LINE__ , ## args); \ |
187 | } \ | 192 | } \ |
188 | } while (0) | 193 | } while (0) |
189 | #else | 194 | #else |
@@ -194,8 +199,8 @@ do { \ | |||
194 | 199 | ||
195 | #undef PDBG | 200 | #undef PDBG |
196 | #define PDBG(fmt, args...) \ | 201 | #define PDBG(fmt, args...) \ |
197 | dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n", \ | 202 | dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", __FILE__, __FUNCTION__, \ |
198 | __FUNCTION__, __LINE__ , ## args) | 203 | __LINE__ , ## args) |
199 | 204 | ||
200 | #undef PDBGG | 205 | #undef PDBGG |
201 | #define PDBGG(fmt, args...) do {;} while(0) /* placeholder */ | 206 | #define PDBGG(fmt, args...) do {;} while(0) /* placeholder */ |
diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c index d0e2b40a7725..89f83354de3b 100644 --- a/drivers/media/video/sn9c102/sn9c102_core.c +++ b/drivers/media/video/sn9c102/sn9c102_core.c | |||
@@ -44,11 +44,12 @@ | |||
44 | /*****************************************************************************/ | 44 | /*****************************************************************************/ |
45 | 45 | ||
46 | #define SN9C102_MODULE_NAME "V4L2 driver for SN9C1xx PC Camera Controllers" | 46 | #define SN9C102_MODULE_NAME "V4L2 driver for SN9C1xx PC Camera Controllers" |
47 | #define SN9C102_MODULE_AUTHOR "(C) 2004-2006 Luca Risolia" | 47 | #define SN9C102_MODULE_ALIAS "sn9c1xx" |
48 | #define SN9C102_MODULE_AUTHOR "(C) 2004-2007 Luca Risolia" | ||
48 | #define SN9C102_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>" | 49 | #define SN9C102_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>" |
49 | #define SN9C102_MODULE_LICENSE "GPL" | 50 | #define SN9C102_MODULE_LICENSE "GPL" |
50 | #define SN9C102_MODULE_VERSION "1:1.34" | 51 | #define SN9C102_MODULE_VERSION "1:1.39" |
51 | #define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 34) | 52 | #define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 39) |
52 | 53 | ||
53 | /*****************************************************************************/ | 54 | /*****************************************************************************/ |
54 | 55 | ||
@@ -56,6 +57,7 @@ MODULE_DEVICE_TABLE(usb, sn9c102_id_table); | |||
56 | 57 | ||
57 | MODULE_AUTHOR(SN9C102_MODULE_AUTHOR " " SN9C102_AUTHOR_EMAIL); | 58 | MODULE_AUTHOR(SN9C102_MODULE_AUTHOR " " SN9C102_AUTHOR_EMAIL); |
58 | MODULE_DESCRIPTION(SN9C102_MODULE_NAME); | 59 | MODULE_DESCRIPTION(SN9C102_MODULE_NAME); |
60 | MODULE_ALIAS(SN9C102_MODULE_ALIAS); | ||
59 | MODULE_VERSION(SN9C102_MODULE_VERSION); | 61 | MODULE_VERSION(SN9C102_MODULE_VERSION); |
60 | MODULE_LICENSE(SN9C102_MODULE_LICENSE); | 62 | MODULE_LICENSE(SN9C102_MODULE_LICENSE); |
61 | 63 | ||
@@ -106,8 +108,7 @@ MODULE_PARM_DESC(debug, | |||
106 | "\n1 = critical errors" | 108 | "\n1 = critical errors" |
107 | "\n2 = significant informations" | 109 | "\n2 = significant informations" |
108 | "\n3 = more verbose messages" | 110 | "\n3 = more verbose messages" |
109 | "\nLevel 3 is useful for testing only, when only " | 111 | "\nLevel 3 is useful for testing only." |
110 | "one device is used." | ||
111 | "\nDefault value is "__MODULE_STRING(SN9C102_DEBUG_LEVEL)"." | 112 | "\nDefault value is "__MODULE_STRING(SN9C102_DEBUG_LEVEL)"." |
112 | "\n"); | 113 | "\n"); |
113 | #endif | 114 | #endif |
@@ -121,8 +122,8 @@ sn9c102_request_buffers(struct sn9c102_device* cam, u32 count, | |||
121 | struct v4l2_pix_format* p = &(cam->sensor.pix_format); | 122 | struct v4l2_pix_format* p = &(cam->sensor.pix_format); |
122 | struct v4l2_rect* r = &(cam->sensor.cropcap.bounds); | 123 | struct v4l2_rect* r = &(cam->sensor.cropcap.bounds); |
123 | size_t imagesize = cam->module_param.force_munmap || io == IO_READ ? | 124 | size_t imagesize = cam->module_param.force_munmap || io == IO_READ ? |
124 | (p->width * p->height * p->priv) / 8 : | 125 | (p->width * p->height * p->priv) / 8 : |
125 | (r->width * r->height * p->priv) / 8; | 126 | (r->width * r->height * p->priv) / 8; |
126 | void* buff = NULL; | 127 | void* buff = NULL; |
127 | u32 i; | 128 | u32 i; |
128 | 129 | ||
@@ -208,27 +209,40 @@ static void sn9c102_queue_unusedframes(struct sn9c102_device* cam) | |||
208 | } | 209 | } |
209 | 210 | ||
210 | /*****************************************************************************/ | 211 | /*****************************************************************************/ |
211 | 212 | /* | |
212 | int sn9c102_write_regs(struct sn9c102_device* cam, u8* buff, u16 index) | 213 | * Write a sequence of count value/register pairs. Returns -1 after the |
214 | * first failed write, or 0 for no errors. | ||
215 | */ | ||
216 | int sn9c102_write_regs(struct sn9c102_device* cam, const u8 valreg[][2], | ||
217 | int count) | ||
213 | { | 218 | { |
214 | struct usb_device* udev = cam->usbdev; | 219 | struct usb_device* udev = cam->usbdev; |
220 | u8* value = cam->control_buffer; /* Needed for DMA'able memory */ | ||
215 | int i, res; | 221 | int i, res; |
216 | 222 | ||
217 | if (index + sizeof(buff) >= ARRAY_SIZE(cam->reg)) | 223 | for (i = 0; i < count; i++) { |
218 | return -1; | 224 | u8 index = valreg[i][1]; |
225 | |||
226 | /* | ||
227 | * index is a u8, so it must be <256 and can't be out of range. | ||
228 | * If we put in a check anyway, gcc annoys us with a warning | ||
229 | * that our check is useless. People get all uppity when they | ||
230 | * see warnings in the kernel compile. | ||
231 | */ | ||
232 | |||
233 | *value = valreg[i][0]; | ||
234 | res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), | ||
235 | 0x08, 0x41, index, 0, | ||
236 | value, 1, SN9C102_CTRL_TIMEOUT); | ||
237 | if (res < 0) { | ||
238 | DBG(3, "Failed to write a register (value 0x%02X, " | ||
239 | "index 0x%02X, error %d)", *value, index, res); | ||
240 | return -1; | ||
241 | } | ||
219 | 242 | ||
220 | res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x08, 0x41, | 243 | cam->reg[index] = *value; |
221 | index, 0, buff, sizeof(buff), | ||
222 | SN9C102_CTRL_TIMEOUT*sizeof(buff)); | ||
223 | if (res < 0) { | ||
224 | DBG(3, "Failed to write registers (index 0x%02X, error %d)", | ||
225 | index, res); | ||
226 | return -1; | ||
227 | } | 244 | } |
228 | 245 | ||
229 | for (i = 0; i < sizeof(buff); i++) | ||
230 | cam->reg[index+i] = buff[i]; | ||
231 | |||
232 | return 0; | 246 | return 0; |
233 | } | 247 | } |
234 | 248 | ||
@@ -485,18 +499,43 @@ static size_t sn9c102_sof_length(struct sn9c102_device* cam) | |||
485 | static void* | 499 | static void* |
486 | sn9c102_find_sof_header(struct sn9c102_device* cam, void* mem, size_t len) | 500 | sn9c102_find_sof_header(struct sn9c102_device* cam, void* mem, size_t len) |
487 | { | 501 | { |
488 | char sof_header[6] = {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96}; | 502 | static const char marker[6] = {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96}; |
489 | size_t soflen = 0, i; | 503 | const char *m = mem; |
504 | size_t soflen = 0, i, j; | ||
490 | 505 | ||
491 | soflen = sn9c102_sof_length(cam); | 506 | soflen = sn9c102_sof_length(cam); |
492 | 507 | ||
493 | for (i = 0; (len >= soflen) && (i <= len - soflen); i++) | 508 | for (i = 0; i < len; i++) { |
494 | if (!memcmp(mem + i, sof_header, sizeof(sof_header))) { | 509 | size_t b; |
495 | memcpy(cam->sof_header, mem + i, | 510 | |
496 | sizeof(sn9c102_sof_header_t)); | 511 | /* Read the variable part of the header */ |
497 | /* Skip the header */ | 512 | if (unlikely(cam->sof.bytesread >= sizeof(marker))) { |
498 | return mem + i + soflen; | 513 | cam->sof.header[cam->sof.bytesread] = *(m+i); |
514 | if (++cam->sof.bytesread == soflen) { | ||
515 | cam->sof.bytesread = 0; | ||
516 | return mem + i; | ||
517 | } | ||
518 | continue; | ||
519 | } | ||
520 | |||
521 | /* Search for the SOF marker (fixed part) in the header */ | ||
522 | for (j = 0, b=cam->sof.bytesread; j+b < sizeof(marker); j++) { | ||
523 | if (unlikely(i+j) == len) | ||
524 | return NULL; | ||
525 | if (*(m+i+j) == marker[cam->sof.bytesread]) { | ||
526 | cam->sof.header[cam->sof.bytesread] = *(m+i+j); | ||
527 | if (++cam->sof.bytesread == sizeof(marker)) { | ||
528 | PDBGG("Bytes to analyze: %zd. SOF " | ||
529 | "starts at byte #%zd", len, i); | ||
530 | i += j+1; | ||
531 | break; | ||
532 | } | ||
533 | } else { | ||
534 | cam->sof.bytesread = 0; | ||
535 | break; | ||
499 | } | 536 | } |
537 | } | ||
538 | } | ||
500 | 539 | ||
501 | return NULL; | 540 | return NULL; |
502 | } | 541 | } |
@@ -505,7 +544,7 @@ sn9c102_find_sof_header(struct sn9c102_device* cam, void* mem, size_t len) | |||
505 | static void* | 544 | static void* |
506 | sn9c102_find_eof_header(struct sn9c102_device* cam, void* mem, size_t len) | 545 | sn9c102_find_eof_header(struct sn9c102_device* cam, void* mem, size_t len) |
507 | { | 546 | { |
508 | char eof_header[4][4] = { | 547 | static const u8 eof_header[4][4] = { |
509 | {0x00, 0x00, 0x00, 0x00}, | 548 | {0x00, 0x00, 0x00, 0x00}, |
510 | {0x40, 0x00, 0x00, 0x00}, | 549 | {0x40, 0x00, 0x00, 0x00}, |
511 | {0x80, 0x00, 0x00, 0x00}, | 550 | {0x80, 0x00, 0x00, 0x00}, |
@@ -513,10 +552,16 @@ sn9c102_find_eof_header(struct sn9c102_device* cam, void* mem, size_t len) | |||
513 | }; | 552 | }; |
514 | size_t i, j; | 553 | size_t i, j; |
515 | 554 | ||
555 | /* The EOF header does not exist in compressed data */ | ||
516 | if (cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X || | 556 | if (cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X || |
517 | cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_JPEG) | 557 | cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_JPEG) |
518 | return NULL; /* EOF header does not exist in compressed data */ | 558 | return NULL; |
519 | 559 | ||
560 | /* | ||
561 | The EOF header might cross the packet boundary, but this is not a | ||
562 | problem, since the end of a frame is determined by checking its size | ||
563 | in the first place. | ||
564 | */ | ||
520 | for (i = 0; (len >= 4) && (i <= len - 4); i++) | 565 | for (i = 0; (len >= 4) && (i <= len - 4); i++) |
521 | for (j = 0; j < ARRAY_SIZE(eof_header); j++) | 566 | for (j = 0; j < ARRAY_SIZE(eof_header); j++) |
522 | if (!memcmp(mem + i, eof_header[j], 4)) | 567 | if (!memcmp(mem + i, eof_header[j], 4)) |
@@ -529,7 +574,7 @@ sn9c102_find_eof_header(struct sn9c102_device* cam, void* mem, size_t len) | |||
529 | static void | 574 | static void |
530 | sn9c102_write_jpegheader(struct sn9c102_device* cam, struct sn9c102_frame_t* f) | 575 | sn9c102_write_jpegheader(struct sn9c102_device* cam, struct sn9c102_frame_t* f) |
531 | { | 576 | { |
532 | static u8 jpeg_header[589] = { | 577 | static const u8 jpeg_header[589] = { |
533 | 0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x06, 0x04, 0x05, | 578 | 0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x06, 0x04, 0x05, |
534 | 0x06, 0x05, 0x04, 0x06, 0x06, 0x05, 0x06, 0x07, 0x07, 0x06, | 579 | 0x06, 0x05, 0x04, 0x06, 0x06, 0x05, 0x06, 0x07, 0x07, 0x06, |
535 | 0x08, 0x0a, 0x10, 0x0a, 0x0a, 0x09, 0x09, 0x0a, 0x14, 0x0e, | 580 | 0x08, 0x0a, 0x10, 0x0a, 0x0a, 0x09, 0x09, 0x0a, 0x14, 0x0e, |
@@ -639,6 +684,7 @@ static void sn9c102_urb_complete(struct urb *urb) | |||
639 | cam->stream = STREAM_OFF; | 684 | cam->stream = STREAM_OFF; |
640 | if ((*f)) | 685 | if ((*f)) |
641 | (*f)->state = F_QUEUED; | 686 | (*f)->state = F_QUEUED; |
687 | cam->sof.bytesread = 0; | ||
642 | DBG(3, "Stream interrupted by application"); | 688 | DBG(3, "Stream interrupted by application"); |
643 | wake_up(&cam->wait_stream); | 689 | wake_up(&cam->wait_stream); |
644 | } | 690 | } |
@@ -676,6 +722,7 @@ static void sn9c102_urb_complete(struct urb *urb) | |||
676 | if (status) { | 722 | if (status) { |
677 | DBG(3, "Error in isochronous frame"); | 723 | DBG(3, "Error in isochronous frame"); |
678 | (*f)->state = F_ERROR; | 724 | (*f)->state = F_ERROR; |
725 | cam->sof.bytesread = 0; | ||
679 | continue; | 726 | continue; |
680 | } | 727 | } |
681 | 728 | ||
@@ -692,13 +739,13 @@ end_of_frame: | |||
692 | if (eof) | 739 | if (eof) |
693 | img = (eof > pos) ? eof - pos - 1 : 0; | 740 | img = (eof > pos) ? eof - pos - 1 : 0; |
694 | 741 | ||
695 | if ((*f)->buf.bytesused+img > imagesize) { | 742 | if ((*f)->buf.bytesused + img > imagesize) { |
696 | u32 b; | 743 | u32 b; |
697 | b = (*f)->buf.bytesused + img - | 744 | b = (*f)->buf.bytesused + img - |
698 | imagesize; | 745 | imagesize; |
699 | img = imagesize - (*f)->buf.bytesused; | 746 | img = imagesize - (*f)->buf.bytesused; |
700 | DBG(3, "Expected EOF not found: " | 747 | PDBGG("Expected EOF not found: video " |
701 | "video frame cut"); | 748 | "frame cut"); |
702 | if (eof) | 749 | if (eof) |
703 | DBG(3, "Exceeded limit: +%u " | 750 | DBG(3, "Exceeded limit: +%u " |
704 | "bytes", (unsigned)(b)); | 751 | "bytes", (unsigned)(b)); |
@@ -719,11 +766,6 @@ end_of_frame: | |||
719 | V4L2_PIX_FMT_JPEG) && eof)) { | 766 | V4L2_PIX_FMT_JPEG) && eof)) { |
720 | u32 b; | 767 | u32 b; |
721 | 768 | ||
722 | if (cam->sensor.pix_format.pixelformat | ||
723 | == V4L2_PIX_FMT_JPEG) | ||
724 | sn9c102_write_eoimarker(cam, | ||
725 | (*f)); | ||
726 | |||
727 | b = (*f)->buf.bytesused; | 769 | b = (*f)->buf.bytesused; |
728 | (*f)->state = F_DONE; | 770 | (*f)->state = F_DONE; |
729 | (*f)->buf.sequence= ++cam->frame_count; | 771 | (*f)->buf.sequence= ++cam->frame_count; |
@@ -741,7 +783,7 @@ end_of_frame: | |||
741 | spin_unlock(&cam->queue_lock); | 783 | spin_unlock(&cam->queue_lock); |
742 | 784 | ||
743 | memcpy(cam->sysfs.frame_header, | 785 | memcpy(cam->sysfs.frame_header, |
744 | cam->sof_header, soflen); | 786 | cam->sof.header, soflen); |
745 | 787 | ||
746 | DBG(3, "Video frame captured: %lu " | 788 | DBG(3, "Video frame captured: %lu " |
747 | "bytes", (unsigned long)(b)); | 789 | "bytes", (unsigned long)(b)); |
@@ -791,7 +833,13 @@ start_of_frame: | |||
791 | V4L2_PIX_FMT_SN9C10X || | 833 | V4L2_PIX_FMT_SN9C10X || |
792 | cam->sensor.pix_format.pixelformat == | 834 | cam->sensor.pix_format.pixelformat == |
793 | V4L2_PIX_FMT_JPEG) { | 835 | V4L2_PIX_FMT_JPEG) { |
794 | eof = sof - soflen; | 836 | if (sof - pos >= soflen) { |
837 | eof = sof - soflen; | ||
838 | } else { /* remove header */ | ||
839 | eof = pos; | ||
840 | (*f)->buf.bytesused -= | ||
841 | (soflen - (sof - pos)); | ||
842 | } | ||
795 | goto end_of_frame; | 843 | goto end_of_frame; |
796 | } else { | 844 | } else { |
797 | DBG(3, "SOF before expected EOF after " | 845 | DBG(3, "SOF before expected EOF after " |
@@ -878,6 +926,7 @@ static int sn9c102_start_transfer(struct sn9c102_device* cam) | |||
878 | } | 926 | } |
879 | 927 | ||
880 | cam->frame_current = NULL; | 928 | cam->frame_current = NULL; |
929 | cam->sof.bytesread = 0; | ||
881 | 930 | ||
882 | for (i = 0; i < SN9C102_URBS; i++) { | 931 | for (i = 0; i < SN9C102_URBS; i++) { |
883 | err = usb_submit_urb(cam->urb[i], GFP_KERNEL); | 932 | err = usb_submit_urb(cam->urb[i], GFP_KERNEL); |
@@ -959,9 +1008,9 @@ static u16 sn9c102_strtou16(const char* buff, size_t len, ssize_t* count) | |||
959 | 1008 | ||
960 | if (len < 6) { | 1009 | if (len < 6) { |
961 | strncpy(str, buff, len); | 1010 | strncpy(str, buff, len); |
962 | str[len+1] = '\0'; | 1011 | str[len] = '\0'; |
963 | } else { | 1012 | } else { |
964 | strncpy(str, buff, 4); | 1013 | strncpy(str, buff, 6); |
965 | str[6] = '\0'; | 1014 | str[6] = '\0'; |
966 | } | 1015 | } |
967 | 1016 | ||
@@ -1062,7 +1111,7 @@ static ssize_t sn9c102_show_val(struct class_device* cd, char* buf) | |||
1062 | 1111 | ||
1063 | count = sprintf(buf, "%d\n", val); | 1112 | count = sprintf(buf, "%d\n", val); |
1064 | 1113 | ||
1065 | DBG(3, "Read bytes: %zd", count); | 1114 | DBG(3, "Read bytes: %zd, value: %d", count, val); |
1066 | 1115 | ||
1067 | mutex_unlock(&sn9c102_sysfs_lock); | 1116 | mutex_unlock(&sn9c102_sysfs_lock); |
1068 | 1117 | ||
@@ -1197,7 +1246,7 @@ static ssize_t sn9c102_show_i2c_val(struct class_device* cd, char* buf) | |||
1197 | 1246 | ||
1198 | count = sprintf(buf, "%d\n", val); | 1247 | count = sprintf(buf, "%d\n", val); |
1199 | 1248 | ||
1200 | DBG(3, "Read bytes: %zd", count); | 1249 | DBG(3, "Read bytes: %zd, value: %d", count, val); |
1201 | 1250 | ||
1202 | mutex_unlock(&sn9c102_sysfs_lock); | 1251 | mutex_unlock(&sn9c102_sysfs_lock); |
1203 | 1252 | ||
@@ -1371,35 +1420,35 @@ static CLASS_DEVICE_ATTR(frame_header, S_IRUGO, | |||
1371 | 1420 | ||
1372 | static int sn9c102_create_sysfs(struct sn9c102_device* cam) | 1421 | static int sn9c102_create_sysfs(struct sn9c102_device* cam) |
1373 | { | 1422 | { |
1374 | struct video_device *v4ldev = cam->v4ldev; | 1423 | struct class_device *classdev = &(cam->v4ldev->class_dev); |
1375 | int err = 0; | 1424 | int err = 0; |
1376 | 1425 | ||
1377 | if ((err = video_device_create_file(v4ldev, &class_device_attr_reg))) | 1426 | if ((err = class_device_create_file(classdev, &class_device_attr_reg))) |
1378 | goto err_out; | 1427 | goto err_out; |
1379 | if ((err = video_device_create_file(v4ldev, &class_device_attr_val))) | 1428 | if ((err = class_device_create_file(classdev, &class_device_attr_val))) |
1380 | goto err_reg; | 1429 | goto err_reg; |
1381 | if ((err = video_device_create_file(v4ldev, | 1430 | if ((err = class_device_create_file(classdev, |
1382 | &class_device_attr_frame_header))) | 1431 | &class_device_attr_frame_header))) |
1383 | goto err_val; | 1432 | goto err_val; |
1384 | 1433 | ||
1385 | if (cam->sensor.sysfs_ops) { | 1434 | if (cam->sensor.sysfs_ops) { |
1386 | if ((err = video_device_create_file(v4ldev, | 1435 | if ((err = class_device_create_file(classdev, |
1387 | &class_device_attr_i2c_reg))) | 1436 | &class_device_attr_i2c_reg))) |
1388 | goto err_frame_header; | 1437 | goto err_frame_header; |
1389 | if ((err = video_device_create_file(v4ldev, | 1438 | if ((err = class_device_create_file(classdev, |
1390 | &class_device_attr_i2c_val))) | 1439 | &class_device_attr_i2c_val))) |
1391 | goto err_i2c_reg; | 1440 | goto err_i2c_reg; |
1392 | } | 1441 | } |
1393 | 1442 | ||
1394 | if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) { | 1443 | if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) { |
1395 | if ((err = video_device_create_file(v4ldev, | 1444 | if ((err = class_device_create_file(classdev, |
1396 | &class_device_attr_green))) | 1445 | &class_device_attr_green))) |
1397 | goto err_i2c_val; | 1446 | goto err_i2c_val; |
1398 | } else { | 1447 | } else { |
1399 | if ((err = video_device_create_file(v4ldev, | 1448 | if ((err = class_device_create_file(classdev, |
1400 | &class_device_attr_blue))) | 1449 | &class_device_attr_blue))) |
1401 | goto err_i2c_val; | 1450 | goto err_i2c_val; |
1402 | if ((err = video_device_create_file(v4ldev, | 1451 | if ((err = class_device_create_file(classdev, |
1403 | &class_device_attr_red))) | 1452 | &class_device_attr_red))) |
1404 | goto err_blue; | 1453 | goto err_blue; |
1405 | } | 1454 | } |
@@ -1407,19 +1456,19 @@ static int sn9c102_create_sysfs(struct sn9c102_device* cam) | |||
1407 | return 0; | 1456 | return 0; |
1408 | 1457 | ||
1409 | err_blue: | 1458 | err_blue: |
1410 | video_device_remove_file(v4ldev, &class_device_attr_blue); | 1459 | class_device_remove_file(classdev, &class_device_attr_blue); |
1411 | err_i2c_val: | 1460 | err_i2c_val: |
1412 | if (cam->sensor.sysfs_ops) | 1461 | if (cam->sensor.sysfs_ops) |
1413 | video_device_remove_file(v4ldev, &class_device_attr_i2c_val); | 1462 | class_device_remove_file(classdev, &class_device_attr_i2c_val); |
1414 | err_i2c_reg: | 1463 | err_i2c_reg: |
1415 | if (cam->sensor.sysfs_ops) | 1464 | if (cam->sensor.sysfs_ops) |
1416 | video_device_remove_file(v4ldev, &class_device_attr_i2c_reg); | 1465 | class_device_remove_file(classdev, &class_device_attr_i2c_reg); |
1417 | err_frame_header: | 1466 | err_frame_header: |
1418 | video_device_remove_file(v4ldev, &class_device_attr_frame_header); | 1467 | class_device_remove_file(classdev, &class_device_attr_frame_header); |
1419 | err_val: | 1468 | err_val: |
1420 | video_device_remove_file(v4ldev, &class_device_attr_val); | 1469 | class_device_remove_file(classdev, &class_device_attr_val); |
1421 | err_reg: | 1470 | err_reg: |
1422 | video_device_remove_file(v4ldev, &class_device_attr_reg); | 1471 | class_device_remove_file(classdev, &class_device_attr_reg); |
1423 | err_out: | 1472 | err_out: |
1424 | return err; | 1473 | return err; |
1425 | } | 1474 | } |
@@ -1477,10 +1526,10 @@ sn9c102_set_compression(struct sn9c102_device* cam, | |||
1477 | case BRIDGE_SN9C101: | 1526 | case BRIDGE_SN9C101: |
1478 | case BRIDGE_SN9C102: | 1527 | case BRIDGE_SN9C102: |
1479 | case BRIDGE_SN9C103: | 1528 | case BRIDGE_SN9C103: |
1480 | if (compression->quality == 0) | 1529 | if (compression->quality == 0) |
1481 | err += sn9c102_write_reg(cam, cam->reg[0x17] | 0x01, | 1530 | err += sn9c102_write_reg(cam, cam->reg[0x17] | 0x01, |
1482 | 0x17); | 1531 | 0x17); |
1483 | else if (compression->quality == 1) | 1532 | else if (compression->quality == 1) |
1484 | err += sn9c102_write_reg(cam, cam->reg[0x17] & 0xfe, | 1533 | err += sn9c102_write_reg(cam, cam->reg[0x17] & 0xfe, |
1485 | 0x17); | 1534 | 0x17); |
1486 | break; | 1535 | break; |
@@ -1489,10 +1538,10 @@ sn9c102_set_compression(struct sn9c102_device* cam, | |||
1489 | if (compression->quality == 0) { | 1538 | if (compression->quality == 0) { |
1490 | for (i = 0; i <= 63; i++) { | 1539 | for (i = 0; i <= 63; i++) { |
1491 | err += sn9c102_write_reg(cam, | 1540 | err += sn9c102_write_reg(cam, |
1492 | SN9C102_Y_QTABLE0[i], | 1541 | SN9C102_Y_QTABLE1[i], |
1493 | 0x100 + i); | 1542 | 0x100 + i); |
1494 | err += sn9c102_write_reg(cam, | 1543 | err += sn9c102_write_reg(cam, |
1495 | SN9C102_UV_QTABLE0[i], | 1544 | SN9C102_UV_QTABLE1[i], |
1496 | 0x140 + i); | 1545 | 0x140 + i); |
1497 | } | 1546 | } |
1498 | err += sn9c102_write_reg(cam, cam->reg[0x18] & 0xbf, | 1547 | err += sn9c102_write_reg(cam, cam->reg[0x18] & 0xbf, |
@@ -1597,9 +1646,13 @@ static int sn9c102_init(struct sn9c102_device* cam) | |||
1597 | if (cam->bridge == BRIDGE_SN9C101 || | 1646 | if (cam->bridge == BRIDGE_SN9C101 || |
1598 | cam->bridge == BRIDGE_SN9C102 || | 1647 | cam->bridge == BRIDGE_SN9C102 || |
1599 | cam->bridge == BRIDGE_SN9C103) { | 1648 | cam->bridge == BRIDGE_SN9C103) { |
1649 | if (s->pix_format.pixelformat == V4L2_PIX_FMT_JPEG) | ||
1650 | s->pix_format.pixelformat= V4L2_PIX_FMT_SBGGR8; | ||
1600 | cam->compression.quality = cam->reg[0x17] & 0x01 ? | 1651 | cam->compression.quality = cam->reg[0x17] & 0x01 ? |
1601 | 0 : 1; | 1652 | 0 : 1; |
1602 | } else { | 1653 | } else { |
1654 | if (s->pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X) | ||
1655 | s->pix_format.pixelformat = V4L2_PIX_FMT_JPEG; | ||
1603 | cam->compression.quality = cam->reg[0x18] & 0x40 ? | 1656 | cam->compression.quality = cam->reg[0x18] & 0x40 ? |
1604 | 0 : 1; | 1657 | 0 : 1; |
1605 | err += sn9c102_set_compression(cam, &cam->compression); | 1658 | err += sn9c102_set_compression(cam, &cam->compression); |
@@ -1805,7 +1858,7 @@ sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos) | |||
1805 | DBG(3, "Close and open the device again to choose " | 1858 | DBG(3, "Close and open the device again to choose " |
1806 | "the read method"); | 1859 | "the read method"); |
1807 | mutex_unlock(&cam->fileop_mutex); | 1860 | mutex_unlock(&cam->fileop_mutex); |
1808 | return -EINVAL; | 1861 | return -EBUSY; |
1809 | } | 1862 | } |
1810 | 1863 | ||
1811 | if (cam->io == IO_NONE) { | 1864 | if (cam->io == IO_NONE) { |
@@ -1845,16 +1898,16 @@ sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos) | |||
1845 | return err; | 1898 | return err; |
1846 | } | 1899 | } |
1847 | } else { | 1900 | } else { |
1848 | timeout = wait_event_interruptible_timeout | 1901 | timeout = wait_event_interruptible_timeout |
1849 | ( cam->wait_frame, | 1902 | ( cam->wait_frame, |
1850 | (!list_empty(&cam->outqueue)) || | 1903 | (!list_empty(&cam->outqueue)) || |
1851 | (cam->state & DEV_DISCONNECTED) || | 1904 | (cam->state & DEV_DISCONNECTED) || |
1852 | (cam->state & DEV_MISCONFIGURED), | 1905 | (cam->state & DEV_MISCONFIGURED), |
1853 | cam->module_param.frame_timeout * | 1906 | cam->module_param.frame_timeout * |
1854 | 1000 * msecs_to_jiffies(1) ); | 1907 | 1000 * msecs_to_jiffies(1) ); |
1855 | if (timeout < 0) { | 1908 | if (timeout < 0) { |
1856 | mutex_unlock(&cam->fileop_mutex); | 1909 | mutex_unlock(&cam->fileop_mutex); |
1857 | return timeout; | 1910 | return timeout; |
1858 | } else if (timeout == 0 && | 1911 | } else if (timeout == 0 && |
1859 | !(cam->state & DEV_DISCONNECTED)) { | 1912 | !(cam->state & DEV_DISCONNECTED)) { |
1860 | DBG(1, "Video frame timeout elapsed"); | 1913 | DBG(1, "Video frame timeout elapsed"); |
@@ -2001,7 +2054,12 @@ static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma) | |||
2001 | return -EIO; | 2054 | return -EIO; |
2002 | } | 2055 | } |
2003 | 2056 | ||
2004 | if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) || | 2057 | if (!(vma->vm_flags & (VM_WRITE | VM_READ))) { |
2058 | mutex_unlock(&cam->fileop_mutex); | ||
2059 | return -EACCES; | ||
2060 | } | ||
2061 | |||
2062 | if (cam->io != IO_MMAP || | ||
2005 | size != PAGE_ALIGN(cam->frame[0].buf.length)) { | 2063 | size != PAGE_ALIGN(cam->frame[0].buf.length)) { |
2006 | mutex_unlock(&cam->fileop_mutex); | 2064 | mutex_unlock(&cam->fileop_mutex); |
2007 | return -EINVAL; | 2065 | return -EINVAL; |
@@ -2267,7 +2325,7 @@ sn9c102_vidioc_s_crop(struct sn9c102_device* cam, void __user * arg) | |||
2267 | if (cam->frame[i].vma_use_count) { | 2325 | if (cam->frame[i].vma_use_count) { |
2268 | DBG(3, "VIDIOC_S_CROP failed. " | 2326 | DBG(3, "VIDIOC_S_CROP failed. " |
2269 | "Unmap the buffers first."); | 2327 | "Unmap the buffers first."); |
2270 | return -EINVAL; | 2328 | return -EBUSY; |
2271 | } | 2329 | } |
2272 | 2330 | ||
2273 | /* Preserve R,G or B origin */ | 2331 | /* Preserve R,G or B origin */ |
@@ -2410,8 +2468,8 @@ sn9c102_vidioc_enum_fmt(struct sn9c102_device* cam, void __user * arg) | |||
2410 | case BRIDGE_SN9C101: | 2468 | case BRIDGE_SN9C101: |
2411 | case BRIDGE_SN9C102: | 2469 | case BRIDGE_SN9C102: |
2412 | case BRIDGE_SN9C103: | 2470 | case BRIDGE_SN9C103: |
2413 | strcpy(fmtd.description, "compressed"); | 2471 | strcpy(fmtd.description, "compressed"); |
2414 | fmtd.pixelformat = V4L2_PIX_FMT_SN9C10X; | 2472 | fmtd.pixelformat = V4L2_PIX_FMT_SN9C10X; |
2415 | break; | 2473 | break; |
2416 | case BRIDGE_SN9C105: | 2474 | case BRIDGE_SN9C105: |
2417 | case BRIDGE_SN9C120: | 2475 | case BRIDGE_SN9C120: |
@@ -2445,8 +2503,10 @@ sn9c102_vidioc_g_fmt(struct sn9c102_device* cam, void __user * arg) | |||
2445 | if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 2503 | if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
2446 | return -EINVAL; | 2504 | return -EINVAL; |
2447 | 2505 | ||
2448 | pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_SN9C10X || | 2506 | pfmt->colorspace = (pfmt->pixelformat == V4L2_PIX_FMT_JPEG) ? |
2449 | pfmt->pixelformat==V4L2_PIX_FMT_JPEG) | 2507 | V4L2_COLORSPACE_JPEG : V4L2_COLORSPACE_SRGB; |
2508 | pfmt->bytesperline = (pfmt->pixelformat == V4L2_PIX_FMT_SN9C10X || | ||
2509 | pfmt->pixelformat == V4L2_PIX_FMT_JPEG) | ||
2450 | ? 0 : (pfmt->width * pfmt->priv) / 8; | 2510 | ? 0 : (pfmt->width * pfmt->priv) / 8; |
2451 | pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8); | 2511 | pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8); |
2452 | pfmt->field = V4L2_FIELD_NONE; | 2512 | pfmt->field = V4L2_FIELD_NONE; |
@@ -2521,9 +2581,9 @@ sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd, | |||
2521 | case BRIDGE_SN9C101: | 2581 | case BRIDGE_SN9C101: |
2522 | case BRIDGE_SN9C102: | 2582 | case BRIDGE_SN9C102: |
2523 | case BRIDGE_SN9C103: | 2583 | case BRIDGE_SN9C103: |
2524 | if (pix->pixelformat != V4L2_PIX_FMT_SN9C10X && | 2584 | if (pix->pixelformat != V4L2_PIX_FMT_SN9C10X && |
2525 | pix->pixelformat != V4L2_PIX_FMT_SBGGR8) | 2585 | pix->pixelformat != V4L2_PIX_FMT_SBGGR8) |
2526 | pix->pixelformat = pfmt->pixelformat; | 2586 | pix->pixelformat = pfmt->pixelformat; |
2527 | break; | 2587 | break; |
2528 | case BRIDGE_SN9C105: | 2588 | case BRIDGE_SN9C105: |
2529 | case BRIDGE_SN9C120: | 2589 | case BRIDGE_SN9C120: |
@@ -2533,7 +2593,8 @@ sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd, | |||
2533 | break; | 2593 | break; |
2534 | } | 2594 | } |
2535 | pix->priv = pfmt->priv; /* bpp */ | 2595 | pix->priv = pfmt->priv; /* bpp */ |
2536 | pix->colorspace = pfmt->colorspace; | 2596 | pix->colorspace = (pix->pixelformat == V4L2_PIX_FMT_JPEG) ? |
2597 | V4L2_COLORSPACE_JPEG : V4L2_COLORSPACE_SRGB; | ||
2537 | pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_SN9C10X || | 2598 | pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_SN9C10X || |
2538 | pix->pixelformat == V4L2_PIX_FMT_JPEG) | 2599 | pix->pixelformat == V4L2_PIX_FMT_JPEG) |
2539 | ? 0 : (pix->width * pix->priv) / 8; | 2600 | ? 0 : (pix->width * pix->priv) / 8; |
@@ -2551,7 +2612,7 @@ sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd, | |||
2551 | if (cam->frame[i].vma_use_count) { | 2612 | if (cam->frame[i].vma_use_count) { |
2552 | DBG(3, "VIDIOC_S_FMT failed. Unmap the " | 2613 | DBG(3, "VIDIOC_S_FMT failed. Unmap the " |
2553 | "buffers first."); | 2614 | "buffers first."); |
2554 | return -EINVAL; | 2615 | return -EBUSY; |
2555 | } | 2616 | } |
2556 | 2617 | ||
2557 | if (cam->stream == STREAM_ON) | 2618 | if (cam->stream == STREAM_ON) |
@@ -2666,14 +2727,14 @@ sn9c102_vidioc_reqbufs(struct sn9c102_device* cam, void __user * arg) | |||
2666 | if (cam->io == IO_READ) { | 2727 | if (cam->io == IO_READ) { |
2667 | DBG(3, "Close and open the device again to choose the mmap " | 2728 | DBG(3, "Close and open the device again to choose the mmap " |
2668 | "I/O method"); | 2729 | "I/O method"); |
2669 | return -EINVAL; | 2730 | return -EBUSY; |
2670 | } | 2731 | } |
2671 | 2732 | ||
2672 | for (i = 0; i < cam->nbuffers; i++) | 2733 | for (i = 0; i < cam->nbuffers; i++) |
2673 | if (cam->frame[i].vma_use_count) { | 2734 | if (cam->frame[i].vma_use_count) { |
2674 | DBG(3, "VIDIOC_REQBUFS failed. Previous buffers are " | 2735 | DBG(3, "VIDIOC_REQBUFS failed. Previous buffers are " |
2675 | "still mapped."); | 2736 | "still mapped."); |
2676 | return -EINVAL; | 2737 | return -EBUSY; |
2677 | } | 2738 | } |
2678 | 2739 | ||
2679 | if (cam->stream == STREAM_ON) | 2740 | if (cam->stream == STREAM_ON) |
@@ -2785,15 +2846,15 @@ sn9c102_vidioc_dqbuf(struct sn9c102_device* cam, struct file* filp, | |||
2785 | if (err) | 2846 | if (err) |
2786 | return err; | 2847 | return err; |
2787 | } else { | 2848 | } else { |
2788 | timeout = wait_event_interruptible_timeout | 2849 | timeout = wait_event_interruptible_timeout |
2789 | ( cam->wait_frame, | 2850 | ( cam->wait_frame, |
2790 | (!list_empty(&cam->outqueue)) || | 2851 | (!list_empty(&cam->outqueue)) || |
2791 | (cam->state & DEV_DISCONNECTED) || | 2852 | (cam->state & DEV_DISCONNECTED) || |
2792 | (cam->state & DEV_MISCONFIGURED), | 2853 | (cam->state & DEV_MISCONFIGURED), |
2793 | cam->module_param.frame_timeout * | 2854 | cam->module_param.frame_timeout * |
2794 | 1000 * msecs_to_jiffies(1) ); | 2855 | 1000 * msecs_to_jiffies(1) ); |
2795 | if (timeout < 0) | 2856 | if (timeout < 0) |
2796 | return timeout; | 2857 | return timeout; |
2797 | else if (timeout == 0 && | 2858 | else if (timeout == 0 && |
2798 | !(cam->state & DEV_DISCONNECTED)) { | 2859 | !(cam->state & DEV_DISCONNECTED)) { |
2799 | DBG(1, "Video frame timeout elapsed"); | 2860 | DBG(1, "Video frame timeout elapsed"); |
@@ -2837,9 +2898,6 @@ sn9c102_vidioc_streamon(struct sn9c102_device* cam, void __user * arg) | |||
2837 | if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP) | 2898 | if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP) |
2838 | return -EINVAL; | 2899 | return -EINVAL; |
2839 | 2900 | ||
2840 | if (list_empty(&cam->inqueue)) | ||
2841 | return -EINVAL; | ||
2842 | |||
2843 | cam->stream = STREAM_ON; | 2901 | cam->stream = STREAM_ON; |
2844 | 2902 | ||
2845 | DBG(3, "Stream on"); | 2903 | DBG(3, "Stream on"); |
@@ -3166,8 +3224,8 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) | |||
3166 | 3224 | ||
3167 | r = sn9c102_read_reg(cam, 0x00); | 3225 | r = sn9c102_read_reg(cam, 0x00); |
3168 | if (r < 0 || (r != 0x10 && r != 0x11 && r != 0x12)) { | 3226 | if (r < 0 || (r != 0x10 && r != 0x11 && r != 0x12)) { |
3169 | DBG(1, "Sorry, this is not a SN9C1xx based camera " | 3227 | DBG(1, "Sorry, this is not a SN9C1xx-based camera " |
3170 | "(vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); | 3228 | "(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); |
3171 | err = -ENODEV; | 3229 | err = -ENODEV; |
3172 | goto fail; | 3230 | goto fail; |
3173 | } | 3231 | } |
@@ -3177,19 +3235,19 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) | |||
3177 | case BRIDGE_SN9C101: | 3235 | case BRIDGE_SN9C101: |
3178 | case BRIDGE_SN9C102: | 3236 | case BRIDGE_SN9C102: |
3179 | DBG(2, "SN9C10[12] PC Camera Controller detected " | 3237 | DBG(2, "SN9C10[12] PC Camera Controller detected " |
3180 | "(vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); | 3238 | "(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); |
3181 | break; | 3239 | break; |
3182 | case BRIDGE_SN9C103: | 3240 | case BRIDGE_SN9C103: |
3183 | DBG(2, "SN9C103 PC Camera Controller detected " | 3241 | DBG(2, "SN9C103 PC Camera Controller detected " |
3184 | "(vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); | 3242 | "(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); |
3185 | break; | 3243 | break; |
3186 | case BRIDGE_SN9C105: | 3244 | case BRIDGE_SN9C105: |
3187 | DBG(2, "SN9C105 PC Camera Controller detected " | 3245 | DBG(2, "SN9C105 PC Camera Controller detected " |
3188 | "(vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); | 3246 | "(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); |
3189 | break; | 3247 | break; |
3190 | case BRIDGE_SN9C120: | 3248 | case BRIDGE_SN9C120: |
3191 | DBG(2, "SN9C120 PC Camera Controller detected " | 3249 | DBG(2, "SN9C120 PC Camera Controller detected " |
3192 | "(vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); | 3250 | "(vid:pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); |
3193 | break; | 3251 | break; |
3194 | } | 3252 | } |
3195 | 3253 | ||
@@ -3260,6 +3318,8 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) | |||
3260 | "device controlling. Error #%d", err); | 3318 | "device controlling. Error #%d", err); |
3261 | #else | 3319 | #else |
3262 | DBG(2, "Optional device control through 'sysfs' interface disabled"); | 3320 | DBG(2, "Optional device control through 'sysfs' interface disabled"); |
3321 | DBG(3, "Compile the kernel with the 'CONFIG_VIDEO_ADV_DEBUG' " | ||
3322 | "configuration option to enable it."); | ||
3263 | #endif | 3323 | #endif |
3264 | 3324 | ||
3265 | usb_set_intfdata(intf, cam); | 3325 | usb_set_intfdata(intf, cam); |
diff --git a/drivers/media/video/sn9c102/sn9c102_devtable.h b/drivers/media/video/sn9c102/sn9c102_devtable.h index 3a682eca6c65..f49bd8c5b86e 100644 --- a/drivers/media/video/sn9c102/sn9c102_devtable.h +++ b/drivers/media/video/sn9c102/sn9c102_devtable.h | |||
@@ -89,16 +89,22 @@ static const struct usb_device_id sn9c102_id_table[] = { | |||
89 | { SN9C102_USB_DEVICE(0x0471, 0x0327, BRIDGE_SN9C105), }, | 89 | { SN9C102_USB_DEVICE(0x0471, 0x0327, BRIDGE_SN9C105), }, |
90 | { SN9C102_USB_DEVICE(0x0471, 0x0328, BRIDGE_SN9C105), }, | 90 | { SN9C102_USB_DEVICE(0x0471, 0x0328, BRIDGE_SN9C105), }, |
91 | { SN9C102_USB_DEVICE(0x0c45, 0x60c0, BRIDGE_SN9C105), }, | 91 | { SN9C102_USB_DEVICE(0x0c45, 0x60c0, BRIDGE_SN9C105), }, |
92 | { SN9C102_USB_DEVICE(0x0c45, 0x60c2, BRIDGE_SN9C105), }, | ||
92 | { SN9C102_USB_DEVICE(0x0c45, 0x60c8, BRIDGE_SN9C105), }, | 93 | { SN9C102_USB_DEVICE(0x0c45, 0x60c8, BRIDGE_SN9C105), }, |
93 | { SN9C102_USB_DEVICE(0x0c45, 0x60cc, BRIDGE_SN9C105), }, | 94 | { SN9C102_USB_DEVICE(0x0c45, 0x60cc, BRIDGE_SN9C105), }, |
94 | { SN9C102_USB_DEVICE(0x0c45, 0x60ea, BRIDGE_SN9C105), }, | 95 | { SN9C102_USB_DEVICE(0x0c45, 0x60ea, BRIDGE_SN9C105), }, |
95 | { SN9C102_USB_DEVICE(0x0c45, 0x60ec, BRIDGE_SN9C105), }, | 96 | { SN9C102_USB_DEVICE(0x0c45, 0x60ec, BRIDGE_SN9C105), }, |
97 | { SN9C102_USB_DEVICE(0x0c45, 0x60ef, BRIDGE_SN9C105), }, | ||
96 | { SN9C102_USB_DEVICE(0x0c45, 0x60fa, BRIDGE_SN9C105), }, | 98 | { SN9C102_USB_DEVICE(0x0c45, 0x60fa, BRIDGE_SN9C105), }, |
97 | { SN9C102_USB_DEVICE(0x0c45, 0x60fb, BRIDGE_SN9C105), }, | 99 | { SN9C102_USB_DEVICE(0x0c45, 0x60fb, BRIDGE_SN9C105), }, |
98 | { SN9C102_USB_DEVICE(0x0c45, 0x60fc, BRIDGE_SN9C105), }, | 100 | { SN9C102_USB_DEVICE(0x0c45, 0x60fc, BRIDGE_SN9C105), }, |
99 | { SN9C102_USB_DEVICE(0x0c45, 0x60fe, BRIDGE_SN9C105), }, | 101 | { SN9C102_USB_DEVICE(0x0c45, 0x60fe, BRIDGE_SN9C105), }, |
100 | /* SN9C120 */ | 102 | /* SN9C120 */ |
103 | { SN9C102_USB_DEVICE(0x0c45, 0x6102, BRIDGE_SN9C120), }, | ||
104 | { SN9C102_USB_DEVICE(0x0c45, 0x6108, BRIDGE_SN9C120), }, | ||
105 | { SN9C102_USB_DEVICE(0x0c45, 0x610f, BRIDGE_SN9C120), }, | ||
101 | { SN9C102_USB_DEVICE(0x0c45, 0x6130, BRIDGE_SN9C120), }, | 106 | { SN9C102_USB_DEVICE(0x0c45, 0x6130, BRIDGE_SN9C120), }, |
107 | { SN9C102_USB_DEVICE(0x0c45, 0x6138, BRIDGE_SN9C120), }, | ||
102 | { SN9C102_USB_DEVICE(0x0c45, 0x613a, BRIDGE_SN9C120), }, | 108 | { SN9C102_USB_DEVICE(0x0c45, 0x613a, BRIDGE_SN9C120), }, |
103 | { SN9C102_USB_DEVICE(0x0c45, 0x613b, BRIDGE_SN9C120), }, | 109 | { SN9C102_USB_DEVICE(0x0c45, 0x613b, BRIDGE_SN9C120), }, |
104 | { SN9C102_USB_DEVICE(0x0c45, 0x613c, BRIDGE_SN9C120), }, | 110 | { SN9C102_USB_DEVICE(0x0c45, 0x613c, BRIDGE_SN9C120), }, |
@@ -114,12 +120,15 @@ static const struct usb_device_id sn9c102_id_table[] = { | |||
114 | Functions must return 0 on success, the appropriate error otherwise. | 120 | Functions must return 0 on success, the appropriate error otherwise. |
115 | */ | 121 | */ |
116 | extern int sn9c102_probe_hv7131d(struct sn9c102_device* cam); | 122 | extern int sn9c102_probe_hv7131d(struct sn9c102_device* cam); |
123 | extern int sn9c102_probe_hv7131r(struct sn9c102_device* cam); | ||
117 | extern int sn9c102_probe_mi0343(struct sn9c102_device* cam); | 124 | extern int sn9c102_probe_mi0343(struct sn9c102_device* cam); |
125 | extern int sn9c102_probe_mi0360(struct sn9c102_device* cam); | ||
118 | extern int sn9c102_probe_ov7630(struct sn9c102_device* cam); | 126 | extern int sn9c102_probe_ov7630(struct sn9c102_device* cam); |
119 | extern int sn9c102_probe_ov7660(struct sn9c102_device* cam); | 127 | extern int sn9c102_probe_ov7660(struct sn9c102_device* cam); |
120 | extern int sn9c102_probe_pas106b(struct sn9c102_device* cam); | 128 | extern int sn9c102_probe_pas106b(struct sn9c102_device* cam); |
121 | extern int sn9c102_probe_pas202bcb(struct sn9c102_device* cam); | 129 | extern int sn9c102_probe_pas202bcb(struct sn9c102_device* cam); |
122 | extern int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam); | 130 | extern int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam); |
131 | extern int sn9c102_probe_tas5110d(struct sn9c102_device* cam); | ||
123 | extern int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam); | 132 | extern int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam); |
124 | 133 | ||
125 | /* | 134 | /* |
@@ -128,13 +137,16 @@ extern int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam); | |||
128 | the order of the list below, from top to bottom. | 137 | the order of the list below, from top to bottom. |
129 | */ | 138 | */ |
130 | static int (*sn9c102_sensor_table[])(struct sn9c102_device*) = { | 139 | static int (*sn9c102_sensor_table[])(struct sn9c102_device*) = { |
140 | &sn9c102_probe_hv7131d, /* strong detection based on SENSOR ids */ | ||
141 | &sn9c102_probe_hv7131r, /* strong detection based on SENSOR ids */ | ||
131 | &sn9c102_probe_mi0343, /* strong detection based on SENSOR ids */ | 142 | &sn9c102_probe_mi0343, /* strong detection based on SENSOR ids */ |
143 | &sn9c102_probe_mi0360, /* strong detection based on SENSOR ids */ | ||
132 | &sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */ | 144 | &sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */ |
133 | &sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */ | 145 | &sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */ |
134 | &sn9c102_probe_hv7131d, /* strong detection based on SENSOR ids */ | ||
135 | &sn9c102_probe_ov7630, /* strong detection based on SENSOR ids */ | 146 | &sn9c102_probe_ov7630, /* strong detection based on SENSOR ids */ |
136 | &sn9c102_probe_ov7660, /* strong detection based on SENSOR ids */ | 147 | &sn9c102_probe_ov7660, /* strong detection based on SENSOR ids */ |
137 | &sn9c102_probe_tas5110c1b, /* detection based on USB pid/vid */ | 148 | &sn9c102_probe_tas5110c1b, /* detection based on USB pid/vid */ |
149 | &sn9c102_probe_tas5110d, /* detection based on USB pid/vid */ | ||
138 | &sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */ | 150 | &sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */ |
139 | NULL, | 151 | NULL, |
140 | }; | 152 | }; |
diff --git a/drivers/media/video/sn9c102/sn9c102_hv7131d.c b/drivers/media/video/sn9c102/sn9c102_hv7131d.c index 7ae368f60d89..28a861aed044 100644 --- a/drivers/media/video/sn9c102/sn9c102_hv7131d.c +++ b/drivers/media/video/sn9c102/sn9c102_hv7131d.c | |||
@@ -22,19 +22,13 @@ | |||
22 | #include "sn9c102_sensor.h" | 22 | #include "sn9c102_sensor.h" |
23 | 23 | ||
24 | 24 | ||
25 | static struct sn9c102_sensor hv7131d; | ||
26 | |||
27 | |||
28 | static int hv7131d_init(struct sn9c102_device* cam) | 25 | static int hv7131d_init(struct sn9c102_device* cam) |
29 | { | 26 | { |
30 | int err = 0; | 27 | int err; |
31 | 28 | ||
32 | err += sn9c102_write_reg(cam, 0x00, 0x10); | 29 | err = sn9c102_write_const_regs(cam, {0x00, 0x10}, {0x00, 0x11}, |
33 | err += sn9c102_write_reg(cam, 0x00, 0x11); | 30 | {0x00, 0x14}, {0x60, 0x17}, |
34 | err += sn9c102_write_reg(cam, 0x00, 0x14); | 31 | {0x0e, 0x18}, {0xf2, 0x19}); |
35 | err += sn9c102_write_reg(cam, 0x60, 0x17); | ||
36 | err += sn9c102_write_reg(cam, 0x0e, 0x18); | ||
37 | err += sn9c102_write_reg(cam, 0xf2, 0x19); | ||
38 | 32 | ||
39 | err += sn9c102_i2c_write(cam, 0x01, 0x04); | 33 | err += sn9c102_i2c_write(cam, 0x01, 0x04); |
40 | err += sn9c102_i2c_write(cam, 0x02, 0x00); | 34 | err += sn9c102_i2c_write(cam, 0x02, 0x00); |
@@ -153,7 +147,7 @@ static int hv7131d_set_pix_format(struct sn9c102_device* cam, | |||
153 | static struct sn9c102_sensor hv7131d = { | 147 | static struct sn9c102_sensor hv7131d = { |
154 | .name = "HV7131D", | 148 | .name = "HV7131D", |
155 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", | 149 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", |
156 | .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103, | 150 | .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102, |
157 | .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, | 151 | .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, |
158 | .frequency = SN9C102_I2C_100KHZ, | 152 | .frequency = SN9C102_I2C_100KHZ, |
159 | .interface = SN9C102_I2C_2WIRES, | 153 | .interface = SN9C102_I2C_2WIRES, |
@@ -250,11 +244,10 @@ static struct sn9c102_sensor hv7131d = { | |||
250 | 244 | ||
251 | int sn9c102_probe_hv7131d(struct sn9c102_device* cam) | 245 | int sn9c102_probe_hv7131d(struct sn9c102_device* cam) |
252 | { | 246 | { |
253 | int r0 = 0, r1 = 0, err = 0; | 247 | int r0 = 0, r1 = 0, err; |
254 | 248 | ||
255 | err += sn9c102_write_reg(cam, 0x01, 0x01); | 249 | err = sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x00, 0x01}, |
256 | err += sn9c102_write_reg(cam, 0x00, 0x01); | 250 | {0x28, 0x17}); |
257 | err += sn9c102_write_reg(cam, 0x28, 0x17); | ||
258 | if (err) | 251 | if (err) |
259 | return -EIO; | 252 | return -EIO; |
260 | 253 | ||
@@ -263,7 +256,7 @@ int sn9c102_probe_hv7131d(struct sn9c102_device* cam) | |||
263 | if (r0 < 0 || r1 < 0) | 256 | if (r0 < 0 || r1 < 0) |
264 | return -EIO; | 257 | return -EIO; |
265 | 258 | ||
266 | if (r0 != 0x00 && r1 != 0x04) | 259 | if (r0 != 0x00 || r1 != 0x04) |
267 | return -ENODEV; | 260 | return -ENODEV; |
268 | 261 | ||
269 | sn9c102_attach_sensor(cam, &hv7131d); | 262 | sn9c102_attach_sensor(cam, &hv7131d); |
diff --git a/drivers/media/video/sn9c102/sn9c102_hv7131r.c b/drivers/media/video/sn9c102/sn9c102_hv7131r.c new file mode 100644 index 000000000000..5a495baa5f95 --- /dev/null +++ b/drivers/media/video/sn9c102/sn9c102_hv7131r.c | |||
@@ -0,0 +1,366 @@ | |||
1 | /*************************************************************************** | ||
2 | * Plug-in for HV7131R image sensor connected to the SN9C1xx PC Camera * | ||
3 | * Controllers * | ||
4 | * * | ||
5 | * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it> * | ||
6 | * * | ||
7 | * This program is free software; you can redistribute it and/or modify * | ||
8 | * it under the terms of the GNU General Public License as published by * | ||
9 | * the Free Software Foundation; either version 2 of the License, or * | ||
10 | * (at your option) any later version. * | ||
11 | * * | ||
12 | * This program is distributed in the hope that it will be useful, * | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
15 | * GNU General Public License for more details. * | ||
16 | * * | ||
17 | * You should have received a copy of the GNU General Public License * | ||
18 | * along with this program; if not, write to the Free Software * | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * | ||
20 | ***************************************************************************/ | ||
21 | |||
22 | #include "sn9c102_sensor.h" | ||
23 | |||
24 | |||
25 | static int hv7131r_init(struct sn9c102_device* cam) | ||
26 | { | ||
27 | int err = 0; | ||
28 | |||
29 | switch (sn9c102_get_bridge(cam)) { | ||
30 | case BRIDGE_SN9C103: | ||
31 | err = sn9c102_write_const_regs(cam, {0x00, 0x03}, {0x1a, 0x04}, | ||
32 | {0x20, 0x05}, {0x20, 0x06}, | ||
33 | {0x03, 0x10}, {0x00, 0x14}, | ||
34 | {0x60, 0x17}, {0x0a, 0x18}, | ||
35 | {0xf0, 0x19}, {0x1d, 0x1a}, | ||
36 | {0x10, 0x1b}, {0x02, 0x1c}, | ||
37 | {0x03, 0x1d}, {0x0f, 0x1e}, | ||
38 | {0x0c, 0x1f}, {0x00, 0x20}, | ||
39 | {0x10, 0x21}, {0x20, 0x22}, | ||
40 | {0x30, 0x23}, {0x40, 0x24}, | ||
41 | {0x50, 0x25}, {0x60, 0x26}, | ||
42 | {0x70, 0x27}, {0x80, 0x28}, | ||
43 | {0x90, 0x29}, {0xa0, 0x2a}, | ||
44 | {0xb0, 0x2b}, {0xc0, 0x2c}, | ||
45 | {0xd0, 0x2d}, {0xe0, 0x2e}, | ||
46 | {0xf0, 0x2f}, {0xff, 0x30}); | ||
47 | |||
48 | break; | ||
49 | case BRIDGE_SN9C105: | ||
50 | case BRIDGE_SN9C120: | ||
51 | err = sn9c102_write_const_regs(cam, {0x44, 0x01}, {0x40, 0x02}, | ||
52 | {0x00, 0x03}, {0x1a, 0x04}, | ||
53 | {0x44, 0x05}, {0x3e, 0x06}, | ||
54 | {0x1a, 0x07}, {0x03, 0x10}, | ||
55 | {0x08, 0x14}, {0xa3, 0x17}, | ||
56 | {0x4b, 0x18}, {0x00, 0x19}, | ||
57 | {0x1d, 0x1a}, {0x10, 0x1b}, | ||
58 | {0x02, 0x1c}, {0x03, 0x1d}, | ||
59 | {0x0f, 0x1e}, {0x0c, 0x1f}, | ||
60 | {0x00, 0x20}, {0x29, 0x21}, | ||
61 | {0x40, 0x22}, {0x54, 0x23}, | ||
62 | {0x66, 0x24}, {0x76, 0x25}, | ||
63 | {0x85, 0x26}, {0x94, 0x27}, | ||
64 | {0xa1, 0x28}, {0xae, 0x29}, | ||
65 | {0xbb, 0x2a}, {0xc7, 0x2b}, | ||
66 | {0xd3, 0x2c}, {0xde, 0x2d}, | ||
67 | {0xea, 0x2e}, {0xf4, 0x2f}, | ||
68 | {0xff, 0x30}, {0x00, 0x3F}, | ||
69 | {0xC7, 0x40}, {0x01, 0x41}, | ||
70 | {0x44, 0x42}, {0x00, 0x43}, | ||
71 | {0x44, 0x44}, {0x00, 0x45}, | ||
72 | {0x44, 0x46}, {0x00, 0x47}, | ||
73 | {0xC7, 0x48}, {0x01, 0x49}, | ||
74 | {0xC7, 0x4A}, {0x01, 0x4B}, | ||
75 | {0xC7, 0x4C}, {0x01, 0x4D}, | ||
76 | {0x44, 0x4E}, {0x00, 0x4F}, | ||
77 | {0x44, 0x50}, {0x00, 0x51}, | ||
78 | {0x44, 0x52}, {0x00, 0x53}, | ||
79 | {0xC7, 0x54}, {0x01, 0x55}, | ||
80 | {0xC7, 0x56}, {0x01, 0x57}, | ||
81 | {0xC7, 0x58}, {0x01, 0x59}, | ||
82 | {0x44, 0x5A}, {0x00, 0x5B}, | ||
83 | {0x44, 0x5C}, {0x00, 0x5D}, | ||
84 | {0x44, 0x5E}, {0x00, 0x5F}, | ||
85 | {0xC7, 0x60}, {0x01, 0x61}, | ||
86 | {0xC7, 0x62}, {0x01, 0x63}, | ||
87 | {0xC7, 0x64}, {0x01, 0x65}, | ||
88 | {0x44, 0x66}, {0x00, 0x67}, | ||
89 | {0x44, 0x68}, {0x00, 0x69}, | ||
90 | {0x44, 0x6A}, {0x00, 0x6B}, | ||
91 | {0xC7, 0x6C}, {0x01, 0x6D}, | ||
92 | {0xC7, 0x6E}, {0x01, 0x6F}, | ||
93 | {0xC7, 0x70}, {0x01, 0x71}, | ||
94 | {0x44, 0x72}, {0x00, 0x73}, | ||
95 | {0x44, 0x74}, {0x00, 0x75}, | ||
96 | {0x44, 0x76}, {0x00, 0x77}, | ||
97 | {0xC7, 0x78}, {0x01, 0x79}, | ||
98 | {0xC7, 0x7A}, {0x01, 0x7B}, | ||
99 | {0xC7, 0x7C}, {0x01, 0x7D}, | ||
100 | {0x44, 0x7E}, {0x00, 0x7F}, | ||
101 | {0x14, 0x84}, {0x00, 0x85}, | ||
102 | {0x27, 0x86}, {0x00, 0x87}, | ||
103 | {0x07, 0x88}, {0x00, 0x89}, | ||
104 | {0xEC, 0x8A}, {0x0f, 0x8B}, | ||
105 | {0xD8, 0x8C}, {0x0f, 0x8D}, | ||
106 | {0x3D, 0x8E}, {0x00, 0x8F}, | ||
107 | {0x3D, 0x90}, {0x00, 0x91}, | ||
108 | {0xCD, 0x92}, {0x0f, 0x93}, | ||
109 | {0xf7, 0x94}, {0x0f, 0x95}, | ||
110 | {0x0C, 0x96}, {0x00, 0x97}, | ||
111 | {0x00, 0x98}, {0x66, 0x99}, | ||
112 | {0x05, 0x9A}, {0x00, 0x9B}, | ||
113 | {0x04, 0x9C}, {0x00, 0x9D}, | ||
114 | {0x08, 0x9E}, {0x00, 0x9F}, | ||
115 | {0x2D, 0xC0}, {0x2D, 0xC1}, | ||
116 | {0x3A, 0xC2}, {0x05, 0xC3}, | ||
117 | {0x04, 0xC4}, {0x3F, 0xC5}, | ||
118 | {0x00, 0xC6}, {0x00, 0xC7}, | ||
119 | {0x50, 0xC8}, {0x3C, 0xC9}, | ||
120 | {0x28, 0xCA}, {0xD8, 0xCB}, | ||
121 | {0x14, 0xCC}, {0xEC, 0xCD}, | ||
122 | {0x32, 0xCE}, {0xDD, 0xCF}, | ||
123 | {0x32, 0xD0}, {0xDD, 0xD1}, | ||
124 | {0x6A, 0xD2}, {0x50, 0xD3}, | ||
125 | {0x00, 0xD4}, {0x00, 0xD5}, | ||
126 | {0x00, 0xD6}); | ||
127 | break; | ||
128 | default: | ||
129 | break; | ||
130 | } | ||
131 | |||
132 | err += sn9c102_i2c_write(cam, 0x20, 0x00); | ||
133 | err += sn9c102_i2c_write(cam, 0x21, 0xd6); | ||
134 | err += sn9c102_i2c_write(cam, 0x25, 0x06); | ||
135 | |||
136 | return err; | ||
137 | } | ||
138 | |||
139 | |||
140 | static int hv7131r_get_ctrl(struct sn9c102_device* cam, | ||
141 | struct v4l2_control* ctrl) | ||
142 | { | ||
143 | switch (ctrl->id) { | ||
144 | case V4L2_CID_GAIN: | ||
145 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x30)) < 0) | ||
146 | return -EIO; | ||
147 | return 0; | ||
148 | case V4L2_CID_RED_BALANCE: | ||
149 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x31)) < 0) | ||
150 | return -EIO; | ||
151 | ctrl->value = ctrl->value & 0x3f; | ||
152 | return 0; | ||
153 | case V4L2_CID_BLUE_BALANCE: | ||
154 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x33)) < 0) | ||
155 | return -EIO; | ||
156 | ctrl->value = ctrl->value & 0x3f; | ||
157 | return 0; | ||
158 | case SN9C102_V4L2_CID_GREEN_BALANCE: | ||
159 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x32)) < 0) | ||
160 | return -EIO; | ||
161 | ctrl->value = ctrl->value & 0x3f; | ||
162 | return 0; | ||
163 | case V4L2_CID_BLACK_LEVEL: | ||
164 | if ((ctrl->value = sn9c102_i2c_read(cam, 0x01)) < 0) | ||
165 | return -EIO; | ||
166 | ctrl->value = (ctrl->value & 0x08) ? 1 : 0; | ||
167 | return 0; | ||
168 | default: | ||
169 | return -EINVAL; | ||
170 | } | ||
171 | } | ||
172 | |||
173 | |||
174 | static int hv7131r_set_ctrl(struct sn9c102_device* cam, | ||
175 | const struct v4l2_control* ctrl) | ||
176 | { | ||
177 | int err = 0; | ||
178 | |||
179 | switch (ctrl->id) { | ||
180 | case V4L2_CID_GAIN: | ||
181 | err += sn9c102_i2c_write(cam, 0x30, ctrl->value); | ||
182 | break; | ||
183 | case V4L2_CID_RED_BALANCE: | ||
184 | err += sn9c102_i2c_write(cam, 0x31, ctrl->value); | ||
185 | break; | ||
186 | case V4L2_CID_BLUE_BALANCE: | ||
187 | err += sn9c102_i2c_write(cam, 0x33, ctrl->value); | ||
188 | break; | ||
189 | case SN9C102_V4L2_CID_GREEN_BALANCE: | ||
190 | err += sn9c102_i2c_write(cam, 0x32, ctrl->value); | ||
191 | break; | ||
192 | case V4L2_CID_BLACK_LEVEL: | ||
193 | { | ||
194 | int r = sn9c102_i2c_read(cam, 0x01); | ||
195 | if (r < 0) | ||
196 | return -EIO; | ||
197 | err += sn9c102_i2c_write(cam, 0x01, | ||
198 | (ctrl->value<<3) | (r&0xf7)); | ||
199 | } | ||
200 | break; | ||
201 | default: | ||
202 | return -EINVAL; | ||
203 | } | ||
204 | |||
205 | return err ? -EIO : 0; | ||
206 | } | ||
207 | |||
208 | |||
209 | static int hv7131r_set_crop(struct sn9c102_device* cam, | ||
210 | const struct v4l2_rect* rect) | ||
211 | { | ||
212 | struct sn9c102_sensor* s = sn9c102_get_sensor(cam); | ||
213 | int err = 0; | ||
214 | u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1, | ||
215 | v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1; | ||
216 | |||
217 | err += sn9c102_write_reg(cam, h_start, 0x12); | ||
218 | err += sn9c102_write_reg(cam, v_start, 0x13); | ||
219 | |||
220 | return err; | ||
221 | } | ||
222 | |||
223 | |||
224 | static int hv7131r_set_pix_format(struct sn9c102_device* cam, | ||
225 | const struct v4l2_pix_format* pix) | ||
226 | { | ||
227 | int err = 0; | ||
228 | |||
229 | switch (sn9c102_get_bridge(cam)) { | ||
230 | case BRIDGE_SN9C103: | ||
231 | if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) { | ||
232 | err += sn9c102_write_reg(cam, 0xa0, 0x19); | ||
233 | err += sn9c102_i2c_write(cam, 0x01, 0x04); | ||
234 | } else { | ||
235 | err += sn9c102_write_reg(cam, 0x30, 0x19); | ||
236 | err += sn9c102_i2c_write(cam, 0x01, 0x04); | ||
237 | } | ||
238 | break; | ||
239 | case BRIDGE_SN9C105: | ||
240 | case BRIDGE_SN9C120: | ||
241 | if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) { | ||
242 | err += sn9c102_write_reg(cam, 0xa5, 0x17); | ||
243 | err += sn9c102_i2c_write(cam, 0x01, 0x24); | ||
244 | } else { | ||
245 | err += sn9c102_write_reg(cam, 0xa3, 0x17); | ||
246 | err += sn9c102_i2c_write(cam, 0x01, 0x04); | ||
247 | } | ||
248 | break; | ||
249 | default: | ||
250 | break; | ||
251 | } | ||
252 | |||
253 | return err; | ||
254 | } | ||
255 | |||
256 | |||
257 | static struct sn9c102_sensor hv7131r = { | ||
258 | .name = "HV7131R", | ||
259 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", | ||
260 | .supported_bridge = BRIDGE_SN9C103 | BRIDGE_SN9C105 | BRIDGE_SN9C120, | ||
261 | .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, | ||
262 | .frequency = SN9C102_I2C_100KHZ, | ||
263 | .interface = SN9C102_I2C_2WIRES, | ||
264 | .i2c_slave_id = 0x11, | ||
265 | .init = &hv7131r_init, | ||
266 | .qctrl = { | ||
267 | { | ||
268 | .id = V4L2_CID_GAIN, | ||
269 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
270 | .name = "global gain", | ||
271 | .minimum = 0x00, | ||
272 | .maximum = 0xff, | ||
273 | .step = 0x01, | ||
274 | .default_value = 0x40, | ||
275 | .flags = 0, | ||
276 | }, | ||
277 | { | ||
278 | .id = V4L2_CID_RED_BALANCE, | ||
279 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
280 | .name = "red balance", | ||
281 | .minimum = 0x00, | ||
282 | .maximum = 0x3f, | ||
283 | .step = 0x01, | ||
284 | .default_value = 0x08, | ||
285 | .flags = 0, | ||
286 | }, | ||
287 | { | ||
288 | .id = V4L2_CID_BLUE_BALANCE, | ||
289 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
290 | .name = "blue balance", | ||
291 | .minimum = 0x00, | ||
292 | .maximum = 0x3f, | ||
293 | .step = 0x01, | ||
294 | .default_value = 0x1a, | ||
295 | .flags = 0, | ||
296 | }, | ||
297 | { | ||
298 | .id = SN9C102_V4L2_CID_GREEN_BALANCE, | ||
299 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
300 | .name = "green balance", | ||
301 | .minimum = 0x00, | ||
302 | .maximum = 0x3f, | ||
303 | .step = 0x01, | ||
304 | .default_value = 0x2f, | ||
305 | .flags = 0, | ||
306 | }, | ||
307 | { | ||
308 | .id = V4L2_CID_BLACK_LEVEL, | ||
309 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
310 | .name = "auto black level compensation", | ||
311 | .minimum = 0x00, | ||
312 | .maximum = 0x01, | ||
313 | .step = 0x01, | ||
314 | .default_value = 0x00, | ||
315 | .flags = 0, | ||
316 | }, | ||
317 | }, | ||
318 | .get_ctrl = &hv7131r_get_ctrl, | ||
319 | .set_ctrl = &hv7131r_set_ctrl, | ||
320 | .cropcap = { | ||
321 | .bounds = { | ||
322 | .left = 0, | ||
323 | .top = 0, | ||
324 | .width = 640, | ||
325 | .height = 480, | ||
326 | }, | ||
327 | .defrect = { | ||
328 | .left = 0, | ||
329 | .top = 0, | ||
330 | .width = 640, | ||
331 | .height = 480, | ||
332 | }, | ||
333 | }, | ||
334 | .set_crop = &hv7131r_set_crop, | ||
335 | .pix_format = { | ||
336 | .width = 640, | ||
337 | .height = 480, | ||
338 | .pixelformat = V4L2_PIX_FMT_SBGGR8, | ||
339 | .priv = 8, | ||
340 | }, | ||
341 | .set_pix_format = &hv7131r_set_pix_format | ||
342 | }; | ||
343 | |||
344 | |||
345 | int sn9c102_probe_hv7131r(struct sn9c102_device* cam) | ||
346 | { | ||
347 | int devid, err; | ||
348 | |||
349 | err = sn9c102_write_const_regs(cam, {0x09, 0x01}, {0x44, 0x02}, | ||
350 | {0x34, 0x01}, {0x20, 0x17}, | ||
351 | {0x34, 0x01}, {0x46, 0x01}); | ||
352 | |||
353 | if (err) | ||
354 | return -EIO; | ||
355 | |||
356 | devid = sn9c102_i2c_try_read(cam, &hv7131r, 0x00); | ||
357 | if (devid < 0) | ||
358 | return -EIO; | ||
359 | |||
360 | if (devid != 0x02) | ||
361 | return -ENODEV; | ||
362 | |||
363 | sn9c102_attach_sensor(cam, &hv7131r); | ||
364 | |||
365 | return 0; | ||
366 | } | ||
diff --git a/drivers/media/video/sn9c102/sn9c102_mi0343.c b/drivers/media/video/sn9c102/sn9c102_mi0343.c index a33d1bc10f90..9200845d011b 100644 --- a/drivers/media/video/sn9c102/sn9c102_mi0343.c +++ b/drivers/media/video/sn9c102/sn9c102_mi0343.c | |||
@@ -22,36 +22,30 @@ | |||
22 | #include "sn9c102_sensor.h" | 22 | #include "sn9c102_sensor.h" |
23 | 23 | ||
24 | 24 | ||
25 | static struct sn9c102_sensor mi0343; | ||
26 | static u8 mi0343_i2c_data[5+1]; | ||
27 | |||
28 | |||
29 | static int mi0343_init(struct sn9c102_device* cam) | 25 | static int mi0343_init(struct sn9c102_device* cam) |
30 | { | 26 | { |
27 | struct sn9c102_sensor* s = sn9c102_get_sensor(cam); | ||
31 | int err = 0; | 28 | int err = 0; |
32 | 29 | ||
33 | err += sn9c102_write_reg(cam, 0x00, 0x10); | 30 | err = sn9c102_write_const_regs(cam, {0x00, 0x10}, {0x00, 0x11}, |
34 | err += sn9c102_write_reg(cam, 0x00, 0x11); | 31 | {0x0a, 0x14}, {0x40, 0x01}, |
35 | err += sn9c102_write_reg(cam, 0x0a, 0x14); | 32 | {0x20, 0x17}, {0x07, 0x18}, |
36 | err += sn9c102_write_reg(cam, 0x40, 0x01); | 33 | {0xa0, 0x19}); |
37 | err += sn9c102_write_reg(cam, 0x20, 0x17); | 34 | |
38 | err += sn9c102_write_reg(cam, 0x07, 0x18); | 35 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d, |
39 | err += sn9c102_write_reg(cam, 0xa0, 0x19); | 36 | 0x00, 0x01, 0, 0); |
40 | 37 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d, | |
41 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id, | 38 | 0x00, 0x00, 0, 0); |
42 | 0x0d, 0x00, 0x01, 0, 0); | 39 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x03, |
43 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id, | 40 | 0x01, 0xe1, 0, 0); |
44 | 0x0d, 0x00, 0x00, 0, 0); | 41 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x04, |
45 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id, | 42 | 0x02, 0x81, 0, 0); |
46 | 0x03, 0x01, 0xe1, 0, 0); | 43 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x05, |
47 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id, | 44 | 0x00, 0x17, 0, 0); |
48 | 0x04, 0x02, 0x81, 0, 0); | 45 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x06, |
49 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id, | 46 | 0x00, 0x11, 0, 0); |
50 | 0x05, 0x00, 0x17, 0, 0); | 47 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x62, |
51 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id, | 48 | 0x04, 0x9a, 0, 0); |
52 | 0x06, 0x00, 0x11, 0, 0); | ||
53 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, mi0343.i2c_slave_id, | ||
54 | 0x62, 0x04, 0x9a, 0, 0); | ||
55 | 49 | ||
56 | return err; | 50 | return err; |
57 | } | 51 | } |
@@ -60,43 +54,46 @@ static int mi0343_init(struct sn9c102_device* cam) | |||
60 | static int mi0343_get_ctrl(struct sn9c102_device* cam, | 54 | static int mi0343_get_ctrl(struct sn9c102_device* cam, |
61 | struct v4l2_control* ctrl) | 55 | struct v4l2_control* ctrl) |
62 | { | 56 | { |
57 | struct sn9c102_sensor* s = sn9c102_get_sensor(cam); | ||
58 | u8 data[5+1]; | ||
59 | |||
63 | switch (ctrl->id) { | 60 | switch (ctrl->id) { |
64 | case V4L2_CID_EXPOSURE: | 61 | case V4L2_CID_EXPOSURE: |
65 | if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, | 62 | if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x09, |
66 | 0x09, 2+1, mi0343_i2c_data) < 0) | 63 | 2+1, data) < 0) |
67 | return -EIO; | 64 | return -EIO; |
68 | ctrl->value = mi0343_i2c_data[2]; | 65 | ctrl->value = data[2]; |
69 | return 0; | 66 | return 0; |
70 | case V4L2_CID_GAIN: | 67 | case V4L2_CID_GAIN: |
71 | if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, | 68 | if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x35, |
72 | 0x35, 2+1, mi0343_i2c_data) < 0) | 69 | 2+1, data) < 0) |
73 | return -EIO; | 70 | return -EIO; |
74 | break; | 71 | break; |
75 | case V4L2_CID_HFLIP: | 72 | case V4L2_CID_HFLIP: |
76 | if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, | 73 | if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20, |
77 | 0x20, 2+1, mi0343_i2c_data) < 0) | 74 | 2+1, data) < 0) |
78 | return -EIO; | 75 | return -EIO; |
79 | ctrl->value = mi0343_i2c_data[3] & 0x20 ? 1 : 0; | 76 | ctrl->value = data[3] & 0x20 ? 1 : 0; |
80 | return 0; | 77 | return 0; |
81 | case V4L2_CID_VFLIP: | 78 | case V4L2_CID_VFLIP: |
82 | if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, | 79 | if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20, |
83 | 0x20, 2+1, mi0343_i2c_data) < 0) | 80 | 2+1, data) < 0) |
84 | return -EIO; | 81 | return -EIO; |
85 | ctrl->value = mi0343_i2c_data[3] & 0x80 ? 1 : 0; | 82 | ctrl->value = data[3] & 0x80 ? 1 : 0; |
86 | return 0; | 83 | return 0; |
87 | case V4L2_CID_RED_BALANCE: | 84 | case V4L2_CID_RED_BALANCE: |
88 | if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, | 85 | if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2d, |
89 | 0x2d, 2+1, mi0343_i2c_data) < 0) | 86 | 2+1, data) < 0) |
90 | return -EIO; | 87 | return -EIO; |
91 | break; | 88 | break; |
92 | case V4L2_CID_BLUE_BALANCE: | 89 | case V4L2_CID_BLUE_BALANCE: |
93 | if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, | 90 | if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2c, |
94 | 0x2c, 2+1, mi0343_i2c_data) < 0) | 91 | 2+1, data) < 0) |
95 | return -EIO; | 92 | return -EIO; |
96 | break; | 93 | break; |
97 | case SN9C102_V4L2_CID_GREEN_BALANCE: | 94 | case SN9C102_V4L2_CID_GREEN_BALANCE: |
98 | if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, | 95 | if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2e, |
99 | 0x2e, 2+1, mi0343_i2c_data) < 0) | 96 | 2+1, data) < 0) |
100 | return -EIO; | 97 | return -EIO; |
101 | break; | 98 | break; |
102 | default: | 99 | default: |
@@ -108,7 +105,7 @@ static int mi0343_get_ctrl(struct sn9c102_device* cam, | |||
108 | case V4L2_CID_RED_BALANCE: | 105 | case V4L2_CID_RED_BALANCE: |
109 | case V4L2_CID_BLUE_BALANCE: | 106 | case V4L2_CID_BLUE_BALANCE: |
110 | case SN9C102_V4L2_CID_GREEN_BALANCE: | 107 | case SN9C102_V4L2_CID_GREEN_BALANCE: |
111 | ctrl->value = mi0343_i2c_data[3] | (mi0343_i2c_data[2] << 8); | 108 | ctrl->value = data[3] | (data[2] << 8); |
112 | if (ctrl->value >= 0x10 && ctrl->value <= 0x3f) | 109 | if (ctrl->value >= 0x10 && ctrl->value <= 0x3f) |
113 | ctrl->value -= 0x10; | 110 | ctrl->value -= 0x10; |
114 | else if (ctrl->value >= 0x60 && ctrl->value <= 0x7f) | 111 | else if (ctrl->value >= 0x60 && ctrl->value <= 0x7f) |
@@ -124,6 +121,7 @@ static int mi0343_get_ctrl(struct sn9c102_device* cam, | |||
124 | static int mi0343_set_ctrl(struct sn9c102_device* cam, | 121 | static int mi0343_set_ctrl(struct sn9c102_device* cam, |
125 | const struct v4l2_control* ctrl) | 122 | const struct v4l2_control* ctrl) |
126 | { | 123 | { |
124 | struct sn9c102_sensor* s = sn9c102_get_sensor(cam); | ||
127 | u16 reg = 0; | 125 | u16 reg = 0; |
128 | int err = 0; | 126 | int err = 0; |
129 | 127 | ||
@@ -143,50 +141,42 @@ static int mi0343_set_ctrl(struct sn9c102_device* cam, | |||
143 | 141 | ||
144 | switch (ctrl->id) { | 142 | switch (ctrl->id) { |
145 | case V4L2_CID_EXPOSURE: | 143 | case V4L2_CID_EXPOSURE: |
146 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, | 144 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, |
147 | mi0343.i2c_slave_id, | ||
148 | 0x09, ctrl->value, 0x00, | 145 | 0x09, ctrl->value, 0x00, |
149 | 0, 0); | 146 | 0, 0); |
150 | break; | 147 | break; |
151 | case V4L2_CID_GAIN: | 148 | case V4L2_CID_GAIN: |
152 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, | 149 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, |
153 | mi0343.i2c_slave_id, | ||
154 | 0x35, reg >> 8, reg & 0xff, | 150 | 0x35, reg >> 8, reg & 0xff, |
155 | 0, 0); | 151 | 0, 0); |
156 | break; | 152 | break; |
157 | case V4L2_CID_HFLIP: | 153 | case V4L2_CID_HFLIP: |
158 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, | 154 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, |
159 | mi0343.i2c_slave_id, | ||
160 | 0x20, ctrl->value ? 0x40:0x00, | 155 | 0x20, ctrl->value ? 0x40:0x00, |
161 | ctrl->value ? 0x20:0x00, | 156 | ctrl->value ? 0x20:0x00, |
162 | 0, 0); | 157 | 0, 0); |
163 | break; | 158 | break; |
164 | case V4L2_CID_VFLIP: | 159 | case V4L2_CID_VFLIP: |
165 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, | 160 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, |
166 | mi0343.i2c_slave_id, | ||
167 | 0x20, ctrl->value ? 0x80:0x00, | 161 | 0x20, ctrl->value ? 0x80:0x00, |
168 | ctrl->value ? 0x80:0x00, | 162 | ctrl->value ? 0x80:0x00, |
169 | 0, 0); | 163 | 0, 0); |
170 | break; | 164 | break; |
171 | case V4L2_CID_RED_BALANCE: | 165 | case V4L2_CID_RED_BALANCE: |
172 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, | 166 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, |
173 | mi0343.i2c_slave_id, | ||
174 | 0x2d, reg >> 8, reg & 0xff, | 167 | 0x2d, reg >> 8, reg & 0xff, |
175 | 0, 0); | 168 | 0, 0); |
176 | break; | 169 | break; |
177 | case V4L2_CID_BLUE_BALANCE: | 170 | case V4L2_CID_BLUE_BALANCE: |
178 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, | 171 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, |
179 | mi0343.i2c_slave_id, | ||
180 | 0x2c, reg >> 8, reg & 0xff, | 172 | 0x2c, reg >> 8, reg & 0xff, |
181 | 0, 0); | 173 | 0, 0); |
182 | break; | 174 | break; |
183 | case SN9C102_V4L2_CID_GREEN_BALANCE: | 175 | case SN9C102_V4L2_CID_GREEN_BALANCE: |
184 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, | 176 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, |
185 | mi0343.i2c_slave_id, | ||
186 | 0x2b, reg >> 8, reg & 0xff, | 177 | 0x2b, reg >> 8, reg & 0xff, |
187 | 0, 0); | 178 | 0, 0); |
188 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, | 179 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, |
189 | mi0343.i2c_slave_id, | ||
190 | 0x2e, reg >> 8, reg & 0xff, | 180 | 0x2e, reg >> 8, reg & 0xff, |
191 | 0, 0); | 181 | 0, 0); |
192 | break; | 182 | break; |
@@ -216,16 +206,15 @@ static int mi0343_set_crop(struct sn9c102_device* cam, | |||
216 | static int mi0343_set_pix_format(struct sn9c102_device* cam, | 206 | static int mi0343_set_pix_format(struct sn9c102_device* cam, |
217 | const struct v4l2_pix_format* pix) | 207 | const struct v4l2_pix_format* pix) |
218 | { | 208 | { |
209 | struct sn9c102_sensor* s = sn9c102_get_sensor(cam); | ||
219 | int err = 0; | 210 | int err = 0; |
220 | 211 | ||
221 | if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) { | 212 | if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) { |
222 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, | 213 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, |
223 | mi0343.i2c_slave_id, | ||
224 | 0x0a, 0x00, 0x03, 0, 0); | 214 | 0x0a, 0x00, 0x03, 0, 0); |
225 | err += sn9c102_write_reg(cam, 0x20, 0x19); | 215 | err += sn9c102_write_reg(cam, 0x20, 0x19); |
226 | } else { | 216 | } else { |
227 | err += sn9c102_i2c_try_raw_write(cam, &mi0343, 4, | 217 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, |
228 | mi0343.i2c_slave_id, | ||
229 | 0x0a, 0x00, 0x05, 0, 0); | 218 | 0x0a, 0x00, 0x05, 0, 0); |
230 | err += sn9c102_write_reg(cam, 0xa0, 0x19); | 219 | err += sn9c102_write_reg(cam, 0xa0, 0x19); |
231 | } | 220 | } |
@@ -237,7 +226,7 @@ static int mi0343_set_pix_format(struct sn9c102_device* cam, | |||
237 | static struct sn9c102_sensor mi0343 = { | 226 | static struct sn9c102_sensor mi0343 = { |
238 | .name = "MI-0343", | 227 | .name = "MI-0343", |
239 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", | 228 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", |
240 | .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103, | 229 | .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102, |
241 | .frequency = SN9C102_I2C_100KHZ, | 230 | .frequency = SN9C102_I2C_100KHZ, |
242 | .interface = SN9C102_I2C_2WIRES, | 231 | .interface = SN9C102_I2C_2WIRES, |
243 | .i2c_slave_id = 0x5d, | 232 | .i2c_slave_id = 0x5d, |
@@ -343,19 +332,20 @@ static struct sn9c102_sensor mi0343 = { | |||
343 | 332 | ||
344 | int sn9c102_probe_mi0343(struct sn9c102_device* cam) | 333 | int sn9c102_probe_mi0343(struct sn9c102_device* cam) |
345 | { | 334 | { |
335 | u8 data[5+1]; | ||
346 | int err = 0; | 336 | int err = 0; |
347 | 337 | ||
348 | err += sn9c102_write_reg(cam, 0x01, 0x01); | 338 | err = sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x00, 0x01}, |
349 | err += sn9c102_write_reg(cam, 0x00, 0x01); | 339 | {0x28, 0x17}); |
350 | err += sn9c102_write_reg(cam, 0x28, 0x17); | 340 | |
351 | if (err) | 341 | if (err) |
352 | return -EIO; | 342 | return -EIO; |
353 | 343 | ||
354 | if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, 0x00, | 344 | if (sn9c102_i2c_try_raw_read(cam, &mi0343, mi0343.i2c_slave_id, 0x00, |
355 | 2, mi0343_i2c_data) < 0) | 345 | 2, data) < 0) |
356 | return -EIO; | 346 | return -EIO; |
357 | 347 | ||
358 | if (mi0343_i2c_data[4] != 0x32 && mi0343_i2c_data[3] != 0xe3) | 348 | if (data[4] != 0x32 || data[3] != 0xe3) |
359 | return -ENODEV; | 349 | return -ENODEV; |
360 | 350 | ||
361 | sn9c102_attach_sensor(cam, &mi0343); | 351 | sn9c102_attach_sensor(cam, &mi0343); |
diff --git a/drivers/media/video/sn9c102/sn9c102_mi0360.c b/drivers/media/video/sn9c102/sn9c102_mi0360.c new file mode 100644 index 000000000000..64698acb0b15 --- /dev/null +++ b/drivers/media/video/sn9c102/sn9c102_mi0360.c | |||
@@ -0,0 +1,338 @@ | |||
1 | /*************************************************************************** | ||
2 | * Plug-in for MI-0360 image sensor connected to the SN9C1xx PC Camera * | ||
3 | * Controllers * | ||
4 | * * | ||
5 | * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it> * | ||
6 | * * | ||
7 | * This program is free software; you can redistribute it and/or modify * | ||
8 | * it under the terms of the GNU General Public License as published by * | ||
9 | * the Free Software Foundation; either version 2 of the License, or * | ||
10 | * (at your option) any later version. * | ||
11 | * * | ||
12 | * This program is distributed in the hope that it will be useful, * | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
15 | * GNU General Public License for more details. * | ||
16 | * * | ||
17 | * You should have received a copy of the GNU General Public License * | ||
18 | * along with this program; if not, write to the Free Software * | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * | ||
20 | ***************************************************************************/ | ||
21 | |||
22 | #include "sn9c102_sensor.h" | ||
23 | |||
24 | |||
25 | static int mi0360_init(struct sn9c102_device* cam) | ||
26 | { | ||
27 | struct sn9c102_sensor* s = sn9c102_get_sensor(cam); | ||
28 | int err = 0; | ||
29 | |||
30 | err = sn9c102_write_const_regs(cam, {0x00, 0x10}, {0x00, 0x11}, | ||
31 | {0x0a, 0x14}, {0x40, 0x01}, | ||
32 | {0x20, 0x17}, {0x07, 0x18}, | ||
33 | {0xa0, 0x19}, {0x02, 0x1c}, | ||
34 | {0x03, 0x1d}, {0x0f, 0x1e}, | ||
35 | {0x0c, 0x1f}, {0x00, 0x20}, | ||
36 | {0x10, 0x21}, {0x20, 0x22}, | ||
37 | {0x30, 0x23}, {0x40, 0x24}, | ||
38 | {0x50, 0x25}, {0x60, 0x26}, | ||
39 | {0x70, 0x27}, {0x80, 0x28}, | ||
40 | {0x90, 0x29}, {0xa0, 0x2a}, | ||
41 | {0xb0, 0x2b}, {0xc0, 0x2c}, | ||
42 | {0xd0, 0x2d}, {0xe0, 0x2e}, | ||
43 | {0xf0, 0x2f}, {0xff, 0x30}); | ||
44 | |||
45 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d, | ||
46 | 0x00, 0x01, 0, 0); | ||
47 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d, | ||
48 | 0x00, 0x00, 0, 0); | ||
49 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x03, | ||
50 | 0x01, 0xe1, 0, 0); | ||
51 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x04, | ||
52 | 0x02, 0x81, 0, 0); | ||
53 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x05, | ||
54 | 0x00, 0x17, 0, 0); | ||
55 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x06, | ||
56 | 0x00, 0x11, 0, 0); | ||
57 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x62, | ||
58 | 0x04, 0x9a, 0, 0); | ||
59 | |||
60 | return err; | ||
61 | } | ||
62 | |||
63 | |||
64 | static int mi0360_get_ctrl(struct sn9c102_device* cam, | ||
65 | struct v4l2_control* ctrl) | ||
66 | { | ||
67 | struct sn9c102_sensor* s = sn9c102_get_sensor(cam); | ||
68 | u8 data[5+1]; | ||
69 | |||
70 | switch (ctrl->id) { | ||
71 | case V4L2_CID_EXPOSURE: | ||
72 | if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x09, | ||
73 | 2+1, data) < 0) | ||
74 | return -EIO; | ||
75 | ctrl->value = data[2]; | ||
76 | return 0; | ||
77 | case V4L2_CID_GAIN: | ||
78 | if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x35, | ||
79 | 2+1, data) < 0) | ||
80 | return -EIO; | ||
81 | ctrl->value = data[3]; | ||
82 | return 0; | ||
83 | case V4L2_CID_RED_BALANCE: | ||
84 | if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2c, | ||
85 | 2+1, data) < 0) | ||
86 | return -EIO; | ||
87 | ctrl->value = data[3]; | ||
88 | return 0; | ||
89 | case V4L2_CID_BLUE_BALANCE: | ||
90 | if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2d, | ||
91 | 2+1, data) < 0) | ||
92 | return -EIO; | ||
93 | ctrl->value = data[3]; | ||
94 | return 0; | ||
95 | case SN9C102_V4L2_CID_GREEN_BALANCE: | ||
96 | if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2e, | ||
97 | 2+1, data) < 0) | ||
98 | return -EIO; | ||
99 | ctrl->value = data[3]; | ||
100 | return 0; | ||
101 | case V4L2_CID_HFLIP: | ||
102 | if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20, | ||
103 | 2+1, data) < 0) | ||
104 | return -EIO; | ||
105 | ctrl->value = data[3] & 0x20 ? 1 : 0; | ||
106 | return 0; | ||
107 | case V4L2_CID_VFLIP: | ||
108 | if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20, | ||
109 | 2+1, data) < 0) | ||
110 | return -EIO; | ||
111 | ctrl->value = data[3] & 0x80 ? 1 : 0; | ||
112 | return 0; | ||
113 | default: | ||
114 | return -EINVAL; | ||
115 | } | ||
116 | |||
117 | return 0; | ||
118 | } | ||
119 | |||
120 | |||
121 | static int mi0360_set_ctrl(struct sn9c102_device* cam, | ||
122 | const struct v4l2_control* ctrl) | ||
123 | { | ||
124 | struct sn9c102_sensor* s = sn9c102_get_sensor(cam); | ||
125 | int err = 0; | ||
126 | |||
127 | switch (ctrl->id) { | ||
128 | case V4L2_CID_EXPOSURE: | ||
129 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, | ||
130 | 0x09, ctrl->value, 0x00, | ||
131 | 0, 0); | ||
132 | break; | ||
133 | case V4L2_CID_GAIN: | ||
134 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, | ||
135 | 0x35, 0x03, ctrl->value, | ||
136 | 0, 0); | ||
137 | break; | ||
138 | case V4L2_CID_RED_BALANCE: | ||
139 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, | ||
140 | 0x2c, 0x03, ctrl->value, | ||
141 | 0, 0); | ||
142 | break; | ||
143 | case V4L2_CID_BLUE_BALANCE: | ||
144 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, | ||
145 | 0x2d, 0x03, ctrl->value, | ||
146 | 0, 0); | ||
147 | break; | ||
148 | case SN9C102_V4L2_CID_GREEN_BALANCE: | ||
149 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, | ||
150 | 0x2b, 0x03, ctrl->value, | ||
151 | 0, 0); | ||
152 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, | ||
153 | 0x2e, 0x03, ctrl->value, | ||
154 | 0, 0); | ||
155 | break; | ||
156 | case V4L2_CID_HFLIP: | ||
157 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, | ||
158 | 0x20, ctrl->value ? 0x40:0x00, | ||
159 | ctrl->value ? 0x20:0x00, | ||
160 | 0, 0); | ||
161 | break; | ||
162 | case V4L2_CID_VFLIP: | ||
163 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, | ||
164 | 0x20, ctrl->value ? 0x80:0x00, | ||
165 | ctrl->value ? 0x80:0x00, | ||
166 | 0, 0); | ||
167 | break; | ||
168 | default: | ||
169 | return -EINVAL; | ||
170 | } | ||
171 | |||
172 | return err ? -EIO : 0; | ||
173 | } | ||
174 | |||
175 | |||
176 | static int mi0360_set_crop(struct sn9c102_device* cam, | ||
177 | const struct v4l2_rect* rect) | ||
178 | { | ||
179 | struct sn9c102_sensor* s = sn9c102_get_sensor(cam); | ||
180 | int err = 0; | ||
181 | u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 0, | ||
182 | v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1; | ||
183 | |||
184 | err += sn9c102_write_reg(cam, h_start, 0x12); | ||
185 | err += sn9c102_write_reg(cam, v_start, 0x13); | ||
186 | |||
187 | return err; | ||
188 | } | ||
189 | |||
190 | |||
191 | static int mi0360_set_pix_format(struct sn9c102_device* cam, | ||
192 | const struct v4l2_pix_format* pix) | ||
193 | { | ||
194 | struct sn9c102_sensor* s = sn9c102_get_sensor(cam); | ||
195 | int err = 0; | ||
196 | |||
197 | if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) { | ||
198 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, | ||
199 | 0x0a, 0x00, 0x02, 0, 0); | ||
200 | err += sn9c102_write_reg(cam, 0x20, 0x19); | ||
201 | } else { | ||
202 | err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, | ||
203 | 0x0a, 0x00, 0x05, 0, 0); | ||
204 | err += sn9c102_write_reg(cam, 0x60, 0x19); | ||
205 | } | ||
206 | |||
207 | return err; | ||
208 | } | ||
209 | |||
210 | |||
211 | static struct sn9c102_sensor mi0360 = { | ||
212 | .name = "MI-0360", | ||
213 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", | ||
214 | .supported_bridge = BRIDGE_SN9C103, | ||
215 | .frequency = SN9C102_I2C_100KHZ, | ||
216 | .interface = SN9C102_I2C_2WIRES, | ||
217 | .i2c_slave_id = 0x5d, | ||
218 | .init = &mi0360_init, | ||
219 | .qctrl = { | ||
220 | { | ||
221 | .id = V4L2_CID_EXPOSURE, | ||
222 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
223 | .name = "exposure", | ||
224 | .minimum = 0x00, | ||
225 | .maximum = 0x0f, | ||
226 | .step = 0x01, | ||
227 | .default_value = 0x05, | ||
228 | .flags = 0, | ||
229 | }, | ||
230 | { | ||
231 | .id = V4L2_CID_GAIN, | ||
232 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
233 | .name = "global gain", | ||
234 | .minimum = 0x00, | ||
235 | .maximum = 0x7f, | ||
236 | .step = 0x01, | ||
237 | .default_value = 0x25, | ||
238 | .flags = 0, | ||
239 | }, | ||
240 | { | ||
241 | .id = V4L2_CID_HFLIP, | ||
242 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
243 | .name = "horizontal mirror", | ||
244 | .minimum = 0, | ||
245 | .maximum = 1, | ||
246 | .step = 1, | ||
247 | .default_value = 0, | ||
248 | .flags = 0, | ||
249 | }, | ||
250 | { | ||
251 | .id = V4L2_CID_VFLIP, | ||
252 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
253 | .name = "vertical mirror", | ||
254 | .minimum = 0, | ||
255 | .maximum = 1, | ||
256 | .step = 1, | ||
257 | .default_value = 0, | ||
258 | .flags = 0, | ||
259 | }, | ||
260 | { | ||
261 | .id = V4L2_CID_BLUE_BALANCE, | ||
262 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
263 | .name = "blue balance", | ||
264 | .minimum = 0x00, | ||
265 | .maximum = 0x7f, | ||
266 | .step = 0x01, | ||
267 | .default_value = 0x0f, | ||
268 | .flags = 0, | ||
269 | }, | ||
270 | { | ||
271 | .id = V4L2_CID_RED_BALANCE, | ||
272 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
273 | .name = "red balance", | ||
274 | .minimum = 0x00, | ||
275 | .maximum = 0x7f, | ||
276 | .step = 0x01, | ||
277 | .default_value = 0x32, | ||
278 | .flags = 0, | ||
279 | }, | ||
280 | { | ||
281 | .id = SN9C102_V4L2_CID_GREEN_BALANCE, | ||
282 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
283 | .name = "green balance", | ||
284 | .minimum = 0x00, | ||
285 | .maximum = 0x7f, | ||
286 | .step = 0x01, | ||
287 | .default_value = 0x25, | ||
288 | .flags = 0, | ||
289 | }, | ||
290 | }, | ||
291 | .get_ctrl = &mi0360_get_ctrl, | ||
292 | .set_ctrl = &mi0360_set_ctrl, | ||
293 | .cropcap = { | ||
294 | .bounds = { | ||
295 | .left = 0, | ||
296 | .top = 0, | ||
297 | .width = 640, | ||
298 | .height = 480, | ||
299 | }, | ||
300 | .defrect = { | ||
301 | .left = 0, | ||
302 | .top = 0, | ||
303 | .width = 640, | ||
304 | .height = 480, | ||
305 | }, | ||
306 | }, | ||
307 | .set_crop = &mi0360_set_crop, | ||
308 | .pix_format = { | ||
309 | .width = 640, | ||
310 | .height = 480, | ||
311 | .pixelformat = V4L2_PIX_FMT_SBGGR8, | ||
312 | .priv = 8, | ||
313 | }, | ||
314 | .set_pix_format = &mi0360_set_pix_format | ||
315 | }; | ||
316 | |||
317 | |||
318 | int sn9c102_probe_mi0360(struct sn9c102_device* cam) | ||
319 | { | ||
320 | u8 data[5+1]; | ||
321 | int err; | ||
322 | |||
323 | err = sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x00, 0x01}, | ||
324 | {0x28, 0x17}); | ||
325 | if (err) | ||
326 | return -EIO; | ||
327 | |||
328 | if (sn9c102_i2c_try_raw_read(cam, &mi0360, mi0360.i2c_slave_id, 0x00, | ||
329 | 2+1, data) < 0) | ||
330 | return -EIO; | ||
331 | |||
332 | if (data[2] != 0x82 || data[3] != 0x43) | ||
333 | return -ENODEV; | ||
334 | |||
335 | sn9c102_attach_sensor(cam, &mi0360); | ||
336 | |||
337 | return 0; | ||
338 | } | ||
diff --git a/drivers/media/video/sn9c102/sn9c102_ov7630.c b/drivers/media/video/sn9c102/sn9c102_ov7630.c index 7df09ff38e63..31b6080b0615 100644 --- a/drivers/media/video/sn9c102/sn9c102_ov7630.c +++ b/drivers/media/video/sn9c102/sn9c102_ov7630.c | |||
@@ -22,9 +22,6 @@ | |||
22 | #include "sn9c102_sensor.h" | 22 | #include "sn9c102_sensor.h" |
23 | 23 | ||
24 | 24 | ||
25 | static struct sn9c102_sensor ov7630; | ||
26 | |||
27 | |||
28 | static int ov7630_init(struct sn9c102_device* cam) | 25 | static int ov7630_init(struct sn9c102_device* cam) |
29 | { | 26 | { |
30 | int err = 0; | 27 | int err = 0; |
@@ -32,21 +29,20 @@ static int ov7630_init(struct sn9c102_device* cam) | |||
32 | switch (sn9c102_get_bridge(cam)) { | 29 | switch (sn9c102_get_bridge(cam)) { |
33 | case BRIDGE_SN9C101: | 30 | case BRIDGE_SN9C101: |
34 | case BRIDGE_SN9C102: | 31 | case BRIDGE_SN9C102: |
35 | err += sn9c102_write_reg(cam, 0x00, 0x14); | 32 | err = sn9c102_write_const_regs(cam, {0x00, 0x14}, |
36 | err += sn9c102_write_reg(cam, 0x60, 0x17); | 33 | {0x60, 0x17}, {0x0f, 0x18}, |
37 | err += sn9c102_write_reg(cam, 0x0f, 0x18); | 34 | {0x50, 0x19}); |
38 | err += sn9c102_write_reg(cam, 0x50, 0x19); | ||
39 | 35 | ||
40 | err += sn9c102_i2c_write(cam, 0x12, 0x8d); | 36 | err += sn9c102_i2c_write(cam, 0x12, 0x8d); |
41 | err += sn9c102_i2c_write(cam, 0x12, 0x0d); | 37 | err += sn9c102_i2c_write(cam, 0x12, 0x0d); |
42 | err += sn9c102_i2c_write(cam, 0x11, 0x00); | 38 | err += sn9c102_i2c_write(cam, 0x11, 0x00); |
43 | err += sn9c102_i2c_write(cam, 0x15, 0x34); | 39 | err += sn9c102_i2c_write(cam, 0x15, 0x35); |
44 | err += sn9c102_i2c_write(cam, 0x16, 0x03); | 40 | err += sn9c102_i2c_write(cam, 0x16, 0x03); |
45 | err += sn9c102_i2c_write(cam, 0x17, 0x1c); | 41 | err += sn9c102_i2c_write(cam, 0x17, 0x1c); |
46 | err += sn9c102_i2c_write(cam, 0x18, 0xbd); | 42 | err += sn9c102_i2c_write(cam, 0x18, 0xbd); |
47 | err += sn9c102_i2c_write(cam, 0x19, 0x06); | 43 | err += sn9c102_i2c_write(cam, 0x19, 0x06); |
48 | err += sn9c102_i2c_write(cam, 0x1a, 0xf6); | 44 | err += sn9c102_i2c_write(cam, 0x1a, 0xf6); |
49 | err += sn9c102_i2c_write(cam, 0x1b, 0x04); | 45 | err += sn9c102_i2c_write(cam, 0x1b, 0x04); |
50 | err += sn9c102_i2c_write(cam, 0x20, 0x44); | 46 | err += sn9c102_i2c_write(cam, 0x20, 0x44); |
51 | err += sn9c102_i2c_write(cam, 0x23, 0xee); | 47 | err += sn9c102_i2c_write(cam, 0x23, 0xee); |
52 | err += sn9c102_i2c_write(cam, 0x26, 0xa0); | 48 | err += sn9c102_i2c_write(cam, 0x26, 0xa0); |
@@ -65,42 +61,26 @@ static int ov7630_init(struct sn9c102_device* cam) | |||
65 | err += sn9c102_i2c_write(cam, 0x71, 0x00); | 61 | err += sn9c102_i2c_write(cam, 0x71, 0x00); |
66 | err += sn9c102_i2c_write(cam, 0x74, 0x21); | 62 | err += sn9c102_i2c_write(cam, 0x74, 0x21); |
67 | err += sn9c102_i2c_write(cam, 0x7d, 0xf7); | 63 | err += sn9c102_i2c_write(cam, 0x7d, 0xf7); |
64 | |||
68 | break; | 65 | break; |
69 | case BRIDGE_SN9C103: | 66 | case BRIDGE_SN9C103: |
70 | err += sn9c102_write_reg(cam, 0x00, 0x02); | 67 | err = sn9c102_write_const_regs(cam, {0x00, 0x02}, {0x00, 0x03}, |
71 | err += sn9c102_write_reg(cam, 0x00, 0x03); | 68 | {0x1a, 0x04}, {0x20, 0x05}, |
72 | err += sn9c102_write_reg(cam, 0x1a, 0x04); | 69 | {0x20, 0x06}, {0x20, 0x07}, |
73 | err += sn9c102_write_reg(cam, 0x20, 0x05); | 70 | {0x03, 0x10}, {0x0a, 0x14}, |
74 | err += sn9c102_write_reg(cam, 0x20, 0x06); | 71 | {0x60, 0x17}, {0x0f, 0x18}, |
75 | err += sn9c102_write_reg(cam, 0x20, 0x07); | 72 | {0x50, 0x19}, {0x1d, 0x1a}, |
76 | err += sn9c102_write_reg(cam, 0x03, 0x10); | 73 | {0x10, 0x1b}, {0x02, 0x1c}, |
77 | err += sn9c102_write_reg(cam, 0x0a, 0x14); | 74 | {0x03, 0x1d}, {0x0f, 0x1e}, |
78 | err += sn9c102_write_reg(cam, 0x60, 0x17); | 75 | {0x0c, 0x1f}, {0x00, 0x20}, |
79 | err += sn9c102_write_reg(cam, 0x0f, 0x18); | 76 | {0x10, 0x21}, {0x20, 0x22}, |
80 | err += sn9c102_write_reg(cam, 0x50, 0x19); | 77 | {0x30, 0x23}, {0x40, 0x24}, |
81 | err += sn9c102_write_reg(cam, 0x1d, 0x1a); | 78 | {0x50, 0x25}, {0x60, 0x26}, |
82 | err += sn9c102_write_reg(cam, 0x10, 0x1b); | 79 | {0x70, 0x27}, {0x80, 0x28}, |
83 | err += sn9c102_write_reg(cam, 0x02, 0x1c); | 80 | {0x90, 0x29}, {0xa0, 0x2a}, |
84 | err += sn9c102_write_reg(cam, 0x03, 0x1d); | 81 | {0xb0, 0x2b}, {0xc0, 0x2c}, |
85 | err += sn9c102_write_reg(cam, 0x0f, 0x1e); | 82 | {0xd0, 0x2d}, {0xe0, 0x2e}, |
86 | err += sn9c102_write_reg(cam, 0x0c, 0x1f); | 83 | {0xf0, 0x2f}, {0xff, 0x30}); |
87 | err += sn9c102_write_reg(cam, 0x00, 0x20); | ||
88 | err += sn9c102_write_reg(cam, 0x10, 0x21); | ||
89 | err += sn9c102_write_reg(cam, 0x20, 0x22); | ||
90 | err += sn9c102_write_reg(cam, 0x30, 0x23); | ||
91 | err += sn9c102_write_reg(cam, 0x40, 0x24); | ||
92 | err += sn9c102_write_reg(cam, 0x50, 0x25); | ||
93 | err += sn9c102_write_reg(cam, 0x60, 0x26); | ||
94 | err += sn9c102_write_reg(cam, 0x70, 0x27); | ||
95 | err += sn9c102_write_reg(cam, 0x80, 0x28); | ||
96 | err += sn9c102_write_reg(cam, 0x90, 0x29); | ||
97 | err += sn9c102_write_reg(cam, 0xa0, 0x2a); | ||
98 | err += sn9c102_write_reg(cam, 0xb0, 0x2b); | ||
99 | err += sn9c102_write_reg(cam, 0xc0, 0x2c); | ||
100 | err += sn9c102_write_reg(cam, 0xd0, 0x2d); | ||
101 | err += sn9c102_write_reg(cam, 0xe0, 0x2e); | ||
102 | err += sn9c102_write_reg(cam, 0xf0, 0x2f); | ||
103 | err += sn9c102_write_reg(cam, 0xff, 0x30); | ||
104 | 84 | ||
105 | err += sn9c102_i2c_write(cam, 0x12, 0x8d); | 85 | err += sn9c102_i2c_write(cam, 0x12, 0x8d); |
106 | err += sn9c102_i2c_write(cam, 0x12, 0x0d); | 86 | err += sn9c102_i2c_write(cam, 0x12, 0x0d); |
@@ -108,23 +88,23 @@ static int ov7630_init(struct sn9c102_device* cam) | |||
108 | err += sn9c102_i2c_write(cam, 0x11, 0x01); | 88 | err += sn9c102_i2c_write(cam, 0x11, 0x01); |
109 | err += sn9c102_i2c_write(cam, 0x1b, 0x04); | 89 | err += sn9c102_i2c_write(cam, 0x1b, 0x04); |
110 | err += sn9c102_i2c_write(cam, 0x20, 0x44); | 90 | err += sn9c102_i2c_write(cam, 0x20, 0x44); |
111 | err += sn9c102_i2c_write(cam, 0x23, 0xee); | 91 | err += sn9c102_i2c_write(cam, 0x23, 0xee); |
112 | err += sn9c102_i2c_write(cam, 0x26, 0xa0); | 92 | err += sn9c102_i2c_write(cam, 0x26, 0xa0); |
113 | err += sn9c102_i2c_write(cam, 0x27, 0x9a); | 93 | err += sn9c102_i2c_write(cam, 0x27, 0x9a); |
114 | err += sn9c102_i2c_write(cam, 0x28, 0x20); | 94 | err += sn9c102_i2c_write(cam, 0x28, 0x20); |
115 | err += sn9c102_i2c_write(cam, 0x29, 0x30); | 95 | err += sn9c102_i2c_write(cam, 0x29, 0x30); |
116 | err += sn9c102_i2c_write(cam, 0x2f, 0x3d); | 96 | err += sn9c102_i2c_write(cam, 0x2f, 0x3d); |
117 | err += sn9c102_i2c_write(cam, 0x30, 0x24); | 97 | err += sn9c102_i2c_write(cam, 0x30, 0x24); |
118 | err += sn9c102_i2c_write(cam, 0x32, 0x86); | 98 | err += sn9c102_i2c_write(cam, 0x32, 0x86); |
119 | err += sn9c102_i2c_write(cam, 0x60, 0xa9); | 99 | err += sn9c102_i2c_write(cam, 0x60, 0xa9); |
120 | err += sn9c102_i2c_write(cam, 0x61, 0x42); | 100 | err += sn9c102_i2c_write(cam, 0x61, 0x42); |
121 | err += sn9c102_i2c_write(cam, 0x65, 0x00); | 101 | err += sn9c102_i2c_write(cam, 0x65, 0x00); |
122 | err += sn9c102_i2c_write(cam, 0x69, 0x38); | 102 | err += sn9c102_i2c_write(cam, 0x69, 0x38); |
123 | err += sn9c102_i2c_write(cam, 0x6f, 0x88); | 103 | err += sn9c102_i2c_write(cam, 0x6f, 0x88); |
124 | err += sn9c102_i2c_write(cam, 0x70, 0x0b); | 104 | err += sn9c102_i2c_write(cam, 0x70, 0x0b); |
125 | err += sn9c102_i2c_write(cam, 0x71, 0x00); | 105 | err += sn9c102_i2c_write(cam, 0x71, 0x00); |
126 | err += sn9c102_i2c_write(cam, 0x74, 0x21); | 106 | err += sn9c102_i2c_write(cam, 0x74, 0x21); |
127 | err += sn9c102_i2c_write(cam, 0x7d, 0xf7); | 107 | err += sn9c102_i2c_write(cam, 0x7d, 0xf7); |
128 | break; | 108 | break; |
129 | default: | 109 | default: |
130 | break; | 110 | break; |
@@ -428,15 +408,14 @@ int sn9c102_probe_ov7630(struct sn9c102_device* cam) | |||
428 | switch (sn9c102_get_bridge(cam)) { | 408 | switch (sn9c102_get_bridge(cam)) { |
429 | case BRIDGE_SN9C101: | 409 | case BRIDGE_SN9C101: |
430 | case BRIDGE_SN9C102: | 410 | case BRIDGE_SN9C102: |
431 | err += sn9c102_write_reg(cam, 0x01, 0x01); | 411 | err = sn9c102_write_const_regs(cam, {0x01, 0x01}, |
432 | err += sn9c102_write_reg(cam, 0x00, 0x01); | 412 | {0x00, 0x01}, {0x28, 0x17}); |
433 | err += sn9c102_write_reg(cam, 0x28, 0x17); | 413 | |
434 | break; | 414 | break; |
435 | case BRIDGE_SN9C103: /* do _not_ change anything! */ | 415 | case BRIDGE_SN9C103: /* do _not_ change anything! */ |
436 | err += sn9c102_write_reg(cam, 0x09, 0x01); | 416 | err = sn9c102_write_const_regs(cam, {0x09, 0x01}, |
437 | err += sn9c102_write_reg(cam, 0x42, 0x01); | 417 | {0x42, 0x01}, {0x28, 0x17}, |
438 | err += sn9c102_write_reg(cam, 0x28, 0x17); | 418 | {0x44, 0x02}); |
439 | err += sn9c102_write_reg(cam, 0x44, 0x02); | ||
440 | pid = sn9c102_i2c_try_read(cam, &ov7630, 0x0a); | 419 | pid = sn9c102_i2c_try_read(cam, &ov7630, 0x0a); |
441 | if (err || pid < 0) { /* try a different initialization */ | 420 | if (err || pid < 0) { /* try a different initialization */ |
442 | err = sn9c102_write_reg(cam, 0x01, 0x01); | 421 | err = sn9c102_write_reg(cam, 0x01, 0x01); |
diff --git a/drivers/media/video/sn9c102/sn9c102_ov7660.c b/drivers/media/video/sn9c102/sn9c102_ov7660.c index d670c24d4435..c898e948fe8d 100644 --- a/drivers/media/video/sn9c102/sn9c102_ov7660.c +++ b/drivers/media/video/sn9c102/sn9c102_ov7660.c | |||
@@ -22,160 +22,84 @@ | |||
22 | #include "sn9c102_sensor.h" | 22 | #include "sn9c102_sensor.h" |
23 | 23 | ||
24 | 24 | ||
25 | static struct sn9c102_sensor ov7660; | ||
26 | |||
27 | |||
28 | static int ov7660_init(struct sn9c102_device* cam) | 25 | static int ov7660_init(struct sn9c102_device* cam) |
29 | { | 26 | { |
30 | int err = 0; | 27 | int err = 0; |
31 | 28 | ||
32 | err += sn9c102_write_reg(cam, 0x40, 0x02); | 29 | err = sn9c102_write_const_regs(cam, {0x40, 0x02}, {0x00, 0x03}, |
33 | err += sn9c102_write_reg(cam, 0x00, 0x03); | 30 | {0x1a, 0x04}, {0x03, 0x10}, |
34 | err += sn9c102_write_reg(cam, 0x1a, 0x04); | 31 | {0x08, 0x14}, {0x20, 0x17}, |
35 | err += sn9c102_write_reg(cam, 0x03, 0x10); | 32 | {0x8b, 0x18}, {0x00, 0x19}, |
36 | err += sn9c102_write_reg(cam, 0x08, 0x14); | 33 | {0x1d, 0x1a}, {0x10, 0x1b}, |
37 | err += sn9c102_write_reg(cam, 0x20, 0x17); | 34 | {0x02, 0x1c}, {0x03, 0x1d}, |
38 | err += sn9c102_write_reg(cam, 0x8b, 0x18); | 35 | {0x0f, 0x1e}, {0x0c, 0x1f}, |
39 | err += sn9c102_write_reg(cam, 0x00, 0x19); | 36 | {0x00, 0x20}, {0x29, 0x21}, |
40 | err += sn9c102_write_reg(cam, 0x1d, 0x1a); | 37 | {0x40, 0x22}, {0x54, 0x23}, |
41 | err += sn9c102_write_reg(cam, 0x10, 0x1b); | 38 | {0x66, 0x24}, {0x76, 0x25}, |
42 | err += sn9c102_write_reg(cam, 0x02, 0x1c); | 39 | {0x85, 0x26}, {0x94, 0x27}, |
43 | err += sn9c102_write_reg(cam, 0x03, 0x1d); | 40 | {0xa1, 0x28}, {0xae, 0x29}, |
44 | err += sn9c102_write_reg(cam, 0x0f, 0x1e); | 41 | {0xbb, 0x2a}, {0xc7, 0x2b}, |
45 | err += sn9c102_write_reg(cam, 0x0c, 0x1f); | 42 | {0xd3, 0x2c}, {0xde, 0x2d}, |
46 | err += sn9c102_write_reg(cam, 0x00, 0x20); | 43 | {0xea, 0x2e}, {0xf4, 0x2f}, |
47 | err += sn9c102_write_reg(cam, 0x29, 0x21); | 44 | {0xff, 0x30}, {0x00, 0x3F}, |
48 | err += sn9c102_write_reg(cam, 0x40, 0x22); | 45 | {0xC7, 0x40}, {0x01, 0x41}, |
49 | err += sn9c102_write_reg(cam, 0x54, 0x23); | 46 | {0x44, 0x42}, {0x00, 0x43}, |
50 | err += sn9c102_write_reg(cam, 0x66, 0x24); | 47 | {0x44, 0x44}, {0x00, 0x45}, |
51 | err += sn9c102_write_reg(cam, 0x76, 0x25); | 48 | {0x44, 0x46}, {0x00, 0x47}, |
52 | err += sn9c102_write_reg(cam, 0x85, 0x26); | 49 | {0xC7, 0x48}, {0x01, 0x49}, |
53 | err += sn9c102_write_reg(cam, 0x94, 0x27); | 50 | {0xC7, 0x4A}, {0x01, 0x4B}, |
54 | err += sn9c102_write_reg(cam, 0xa1, 0x28); | 51 | {0xC7, 0x4C}, {0x01, 0x4D}, |
55 | err += sn9c102_write_reg(cam, 0xae, 0x29); | 52 | {0x44, 0x4E}, {0x00, 0x4F}, |
56 | err += sn9c102_write_reg(cam, 0xbb, 0x2a); | 53 | {0x44, 0x50}, {0x00, 0x51}, |
57 | err += sn9c102_write_reg(cam, 0xc7, 0x2b); | 54 | {0x44, 0x52}, {0x00, 0x53}, |
58 | err += sn9c102_write_reg(cam, 0xd3, 0x2c); | 55 | {0xC7, 0x54}, {0x01, 0x55}, |
59 | err += sn9c102_write_reg(cam, 0xde, 0x2d); | 56 | {0xC7, 0x56}, {0x01, 0x57}, |
60 | err += sn9c102_write_reg(cam, 0xea, 0x2e); | 57 | {0xC7, 0x58}, {0x01, 0x59}, |
61 | err += sn9c102_write_reg(cam, 0xf4, 0x2f); | 58 | {0x44, 0x5A}, {0x00, 0x5B}, |
62 | err += sn9c102_write_reg(cam, 0xff, 0x30); | 59 | {0x44, 0x5C}, {0x00, 0x5D}, |
63 | err += sn9c102_write_reg(cam, 0x00, 0x3F); | 60 | {0x44, 0x5E}, {0x00, 0x5F}, |
64 | err += sn9c102_write_reg(cam, 0xC7, 0x40); | 61 | {0xC7, 0x60}, {0x01, 0x61}, |
65 | err += sn9c102_write_reg(cam, 0x01, 0x41); | 62 | {0xC7, 0x62}, {0x01, 0x63}, |
66 | err += sn9c102_write_reg(cam, 0x44, 0x42); | 63 | {0xC7, 0x64}, {0x01, 0x65}, |
67 | err += sn9c102_write_reg(cam, 0x00, 0x43); | 64 | {0x44, 0x66}, {0x00, 0x67}, |
68 | err += sn9c102_write_reg(cam, 0x44, 0x44); | 65 | {0x44, 0x68}, {0x00, 0x69}, |
69 | err += sn9c102_write_reg(cam, 0x00, 0x45); | 66 | {0x44, 0x6A}, {0x00, 0x6B}, |
70 | err += sn9c102_write_reg(cam, 0x44, 0x46); | 67 | {0xC7, 0x6C}, {0x01, 0x6D}, |
71 | err += sn9c102_write_reg(cam, 0x00, 0x47); | 68 | {0xC7, 0x6E}, {0x01, 0x6F}, |
72 | err += sn9c102_write_reg(cam, 0xC7, 0x48); | 69 | {0xC7, 0x70}, {0x01, 0x71}, |
73 | err += sn9c102_write_reg(cam, 0x01, 0x49); | 70 | {0x44, 0x72}, {0x00, 0x73}, |
74 | err += sn9c102_write_reg(cam, 0xC7, 0x4A); | 71 | {0x44, 0x74}, {0x00, 0x75}, |
75 | err += sn9c102_write_reg(cam, 0x01, 0x4B); | 72 | {0x44, 0x76}, {0x00, 0x77}, |
76 | err += sn9c102_write_reg(cam, 0xC7, 0x4C); | 73 | {0xC7, 0x78}, {0x01, 0x79}, |
77 | err += sn9c102_write_reg(cam, 0x01, 0x4D); | 74 | {0xC7, 0x7A}, {0x01, 0x7B}, |
78 | err += sn9c102_write_reg(cam, 0x44, 0x4E); | 75 | {0xC7, 0x7C}, {0x01, 0x7D}, |
79 | err += sn9c102_write_reg(cam, 0x00, 0x4F); | 76 | {0x44, 0x7E}, {0x00, 0x7F}, |
80 | err += sn9c102_write_reg(cam, 0x44, 0x50); | 77 | {0x14, 0x84}, {0x00, 0x85}, |
81 | err += sn9c102_write_reg(cam, 0x00, 0x51); | 78 | {0x27, 0x86}, {0x00, 0x87}, |
82 | err += sn9c102_write_reg(cam, 0x44, 0x52); | 79 | {0x07, 0x88}, {0x00, 0x89}, |
83 | err += sn9c102_write_reg(cam, 0x00, 0x53); | 80 | {0xEC, 0x8A}, {0x0f, 0x8B}, |
84 | err += sn9c102_write_reg(cam, 0xC7, 0x54); | 81 | {0xD8, 0x8C}, {0x0f, 0x8D}, |
85 | err += sn9c102_write_reg(cam, 0x01, 0x55); | 82 | {0x3D, 0x8E}, {0x00, 0x8F}, |
86 | err += sn9c102_write_reg(cam, 0xC7, 0x56); | 83 | {0x3D, 0x90}, {0x00, 0x91}, |
87 | err += sn9c102_write_reg(cam, 0x01, 0x57); | 84 | {0xCD, 0x92}, {0x0f, 0x93}, |
88 | err += sn9c102_write_reg(cam, 0xC7, 0x58); | 85 | {0xf7, 0x94}, {0x0f, 0x95}, |
89 | err += sn9c102_write_reg(cam, 0x01, 0x59); | 86 | {0x0C, 0x96}, {0x00, 0x97}, |
90 | err += sn9c102_write_reg(cam, 0x44, 0x5A); | 87 | {0x00, 0x98}, {0x66, 0x99}, |
91 | err += sn9c102_write_reg(cam, 0x00, 0x5B); | 88 | {0x05, 0x9A}, {0x00, 0x9B}, |
92 | err += sn9c102_write_reg(cam, 0x44, 0x5C); | 89 | {0x04, 0x9C}, {0x00, 0x9D}, |
93 | err += sn9c102_write_reg(cam, 0x00, 0x5D); | 90 | {0x08, 0x9E}, {0x00, 0x9F}, |
94 | err += sn9c102_write_reg(cam, 0x44, 0x5E); | 91 | {0x2D, 0xC0}, {0x2D, 0xC1}, |
95 | err += sn9c102_write_reg(cam, 0x00, 0x5F); | 92 | {0x3A, 0xC2}, {0x05, 0xC3}, |
96 | err += sn9c102_write_reg(cam, 0xC7, 0x60); | 93 | {0x04, 0xC4}, {0x3F, 0xC5}, |
97 | err += sn9c102_write_reg(cam, 0x01, 0x61); | 94 | {0x00, 0xC6}, {0x00, 0xC7}, |
98 | err += sn9c102_write_reg(cam, 0xC7, 0x62); | 95 | {0x50, 0xC8}, {0x3C, 0xC9}, |
99 | err += sn9c102_write_reg(cam, 0x01, 0x63); | 96 | {0x28, 0xCA}, {0xD8, 0xCB}, |
100 | err += sn9c102_write_reg(cam, 0xC7, 0x64); | 97 | {0x14, 0xCC}, {0xEC, 0xCD}, |
101 | err += sn9c102_write_reg(cam, 0x01, 0x65); | 98 | {0x32, 0xCE}, {0xDD, 0xCF}, |
102 | err += sn9c102_write_reg(cam, 0x44, 0x66); | 99 | {0x32, 0xD0}, {0xDD, 0xD1}, |
103 | err += sn9c102_write_reg(cam, 0x00, 0x67); | 100 | {0x6A, 0xD2}, {0x50, 0xD3}, |
104 | err += sn9c102_write_reg(cam, 0x44, 0x68); | 101 | {0x00, 0xD4}, {0x00, 0xD5}, |
105 | err += sn9c102_write_reg(cam, 0x00, 0x69); | 102 | {0x00, 0xD6}); |
106 | err += sn9c102_write_reg(cam, 0x44, 0x6A); | ||
107 | err += sn9c102_write_reg(cam, 0x00, 0x6B); | ||
108 | err += sn9c102_write_reg(cam, 0xC7, 0x6C); | ||
109 | err += sn9c102_write_reg(cam, 0x01, 0x6D); | ||
110 | err += sn9c102_write_reg(cam, 0xC7, 0x6E); | ||
111 | err += sn9c102_write_reg(cam, 0x01, 0x6F); | ||
112 | err += sn9c102_write_reg(cam, 0xC7, 0x70); | ||
113 | err += sn9c102_write_reg(cam, 0x01, 0x71); | ||
114 | err += sn9c102_write_reg(cam, 0x44, 0x72); | ||
115 | err += sn9c102_write_reg(cam, 0x00, 0x73); | ||
116 | err += sn9c102_write_reg(cam, 0x44, 0x74); | ||
117 | err += sn9c102_write_reg(cam, 0x00, 0x75); | ||
118 | err += sn9c102_write_reg(cam, 0x44, 0x76); | ||
119 | err += sn9c102_write_reg(cam, 0x00, 0x77); | ||
120 | err += sn9c102_write_reg(cam, 0xC7, 0x78); | ||
121 | err += sn9c102_write_reg(cam, 0x01, 0x79); | ||
122 | err += sn9c102_write_reg(cam, 0xC7, 0x7A); | ||
123 | err += sn9c102_write_reg(cam, 0x01, 0x7B); | ||
124 | err += sn9c102_write_reg(cam, 0xC7, 0x7C); | ||
125 | err += sn9c102_write_reg(cam, 0x01, 0x7D); | ||
126 | err += sn9c102_write_reg(cam, 0x44, 0x7E); | ||
127 | err += sn9c102_write_reg(cam, 0x00, 0x7F); | ||
128 | err += sn9c102_write_reg(cam, 0x14, 0x84); | ||
129 | err += sn9c102_write_reg(cam, 0x00, 0x85); | ||
130 | err += sn9c102_write_reg(cam, 0x27, 0x86); | ||
131 | err += sn9c102_write_reg(cam, 0x00, 0x87); | ||
132 | err += sn9c102_write_reg(cam, 0x07, 0x88); | ||
133 | err += sn9c102_write_reg(cam, 0x00, 0x89); | ||
134 | err += sn9c102_write_reg(cam, 0xEC, 0x8A); | ||
135 | err += sn9c102_write_reg(cam, 0x0f, 0x8B); | ||
136 | err += sn9c102_write_reg(cam, 0xD8, 0x8C); | ||
137 | err += sn9c102_write_reg(cam, 0x0f, 0x8D); | ||
138 | err += sn9c102_write_reg(cam, 0x3D, 0x8E); | ||
139 | err += sn9c102_write_reg(cam, 0x00, 0x8F); | ||
140 | err += sn9c102_write_reg(cam, 0x3D, 0x90); | ||
141 | err += sn9c102_write_reg(cam, 0x00, 0x91); | ||
142 | err += sn9c102_write_reg(cam, 0xCD, 0x92); | ||
143 | err += sn9c102_write_reg(cam, 0x0f, 0x93); | ||
144 | err += sn9c102_write_reg(cam, 0xf7, 0x94); | ||
145 | err += sn9c102_write_reg(cam, 0x0f, 0x95); | ||
146 | err += sn9c102_write_reg(cam, 0x0C, 0x96); | ||
147 | err += sn9c102_write_reg(cam, 0x00, 0x97); | ||
148 | err += sn9c102_write_reg(cam, 0x00, 0x98); | ||
149 | err += sn9c102_write_reg(cam, 0x66, 0x99); | ||
150 | err += sn9c102_write_reg(cam, 0x05, 0x9A); | ||
151 | err += sn9c102_write_reg(cam, 0x00, 0x9B); | ||
152 | err += sn9c102_write_reg(cam, 0x04, 0x9C); | ||
153 | err += sn9c102_write_reg(cam, 0x00, 0x9D); | ||
154 | err += sn9c102_write_reg(cam, 0x08, 0x9E); | ||
155 | err += sn9c102_write_reg(cam, 0x00, 0x9F); | ||
156 | err += sn9c102_write_reg(cam, 0x2D, 0xC0); | ||
157 | err += sn9c102_write_reg(cam, 0x2D, 0xC1); | ||
158 | err += sn9c102_write_reg(cam, 0x3A, 0xC2); | ||
159 | err += sn9c102_write_reg(cam, 0x05, 0xC3); | ||
160 | err += sn9c102_write_reg(cam, 0x04, 0xC4); | ||
161 | err += sn9c102_write_reg(cam, 0x3F, 0xC5); | ||
162 | err += sn9c102_write_reg(cam, 0x00, 0xC6); | ||
163 | err += sn9c102_write_reg(cam, 0x00, 0xC7); | ||
164 | err += sn9c102_write_reg(cam, 0x50, 0xC8); | ||
165 | err += sn9c102_write_reg(cam, 0x3C, 0xC9); | ||
166 | err += sn9c102_write_reg(cam, 0x28, 0xCA); | ||
167 | err += sn9c102_write_reg(cam, 0xD8, 0xCB); | ||
168 | err += sn9c102_write_reg(cam, 0x14, 0xCC); | ||
169 | err += sn9c102_write_reg(cam, 0xEC, 0xCD); | ||
170 | err += sn9c102_write_reg(cam, 0x32, 0xCE); | ||
171 | err += sn9c102_write_reg(cam, 0xDD, 0xCF); | ||
172 | err += sn9c102_write_reg(cam, 0x32, 0xD0); | ||
173 | err += sn9c102_write_reg(cam, 0xDD, 0xD1); | ||
174 | err += sn9c102_write_reg(cam, 0x6A, 0xD2); | ||
175 | err += sn9c102_write_reg(cam, 0x50, 0xD3); | ||
176 | err += sn9c102_write_reg(cam, 0x00, 0xD4); | ||
177 | err += sn9c102_write_reg(cam, 0x00, 0xD5); | ||
178 | err += sn9c102_write_reg(cam, 0x00, 0xD6); | ||
179 | 103 | ||
180 | err += sn9c102_i2c_write(cam, 0x12, 0x80); | 104 | err += sn9c102_i2c_write(cam, 0x12, 0x80); |
181 | err += sn9c102_i2c_write(cam, 0x11, 0x09); | 105 | err += sn9c102_i2c_write(cam, 0x11, 0x09); |
@@ -572,13 +496,11 @@ static struct sn9c102_sensor ov7660 = { | |||
572 | 496 | ||
573 | int sn9c102_probe_ov7660(struct sn9c102_device* cam) | 497 | int sn9c102_probe_ov7660(struct sn9c102_device* cam) |
574 | { | 498 | { |
575 | int pid, ver, err = 0; | 499 | int pid, ver, err; |
576 | 500 | ||
577 | err += sn9c102_write_reg(cam, 0x01, 0xf1); | 501 | err = sn9c102_write_const_regs(cam, {0x01, 0xf1}, {0x00, 0xf1}, |
578 | err += sn9c102_write_reg(cam, 0x00, 0xf1); | 502 | {0x01, 0x01}, {0x00, 0x01}, |
579 | err += sn9c102_write_reg(cam, 0x01, 0x01); | 503 | {0x28, 0x17}); |
580 | err += sn9c102_write_reg(cam, 0x00, 0x01); | ||
581 | err += sn9c102_write_reg(cam, 0x28, 0x17); | ||
582 | 504 | ||
583 | pid = sn9c102_i2c_try_read(cam, &ov7660, 0x0a); | 505 | pid = sn9c102_i2c_try_read(cam, &ov7660, 0x0a); |
584 | ver = sn9c102_i2c_try_read(cam, &ov7660, 0x0b); | 506 | ver = sn9c102_i2c_try_read(cam, &ov7660, 0x0b); |
diff --git a/drivers/media/video/sn9c102/sn9c102_pas106b.c b/drivers/media/video/sn9c102/sn9c102_pas106b.c index 8d79a5fae5de..67151964801f 100644 --- a/drivers/media/video/sn9c102/sn9c102_pas106b.c +++ b/drivers/media/video/sn9c102/sn9c102_pas106b.c | |||
@@ -23,19 +23,13 @@ | |||
23 | #include "sn9c102_sensor.h" | 23 | #include "sn9c102_sensor.h" |
24 | 24 | ||
25 | 25 | ||
26 | static struct sn9c102_sensor pas106b; | ||
27 | |||
28 | |||
29 | static int pas106b_init(struct sn9c102_device* cam) | 26 | static int pas106b_init(struct sn9c102_device* cam) |
30 | { | 27 | { |
31 | int err = 0; | 28 | int err = 0; |
32 | 29 | ||
33 | err += sn9c102_write_reg(cam, 0x00, 0x10); | 30 | err = sn9c102_write_const_regs(cam, {0x00, 0x10}, {0x00, 0x11}, |
34 | err += sn9c102_write_reg(cam, 0x00, 0x11); | 31 | {0x00, 0x14}, {0x20, 0x17}, |
35 | err += sn9c102_write_reg(cam, 0x00, 0x14); | 32 | {0x20, 0x19}, {0x09, 0x18}); |
36 | err += sn9c102_write_reg(cam, 0x20, 0x17); | ||
37 | err += sn9c102_write_reg(cam, 0x20, 0x19); | ||
38 | err += sn9c102_write_reg(cam, 0x09, 0x18); | ||
39 | 33 | ||
40 | err += sn9c102_i2c_write(cam, 0x02, 0x0c); | 34 | err += sn9c102_i2c_write(cam, 0x02, 0x0c); |
41 | err += sn9c102_i2c_write(cam, 0x05, 0x5a); | 35 | err += sn9c102_i2c_write(cam, 0x05, 0x5a); |
@@ -172,7 +166,7 @@ static int pas106b_set_pix_format(struct sn9c102_device* cam, | |||
172 | static struct sn9c102_sensor pas106b = { | 166 | static struct sn9c102_sensor pas106b = { |
173 | .name = "PAS106B", | 167 | .name = "PAS106B", |
174 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", | 168 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", |
175 | .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103, | 169 | .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102, |
176 | .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, | 170 | .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE, |
177 | .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ, | 171 | .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ, |
178 | .interface = SN9C102_I2C_2WIRES, | 172 | .interface = SN9C102_I2C_2WIRES, |
@@ -279,16 +273,17 @@ static struct sn9c102_sensor pas106b = { | |||
279 | 273 | ||
280 | int sn9c102_probe_pas106b(struct sn9c102_device* cam) | 274 | int sn9c102_probe_pas106b(struct sn9c102_device* cam) |
281 | { | 275 | { |
282 | int r0 = 0, r1 = 0, err = 0; | 276 | int r0 = 0, r1 = 0, err; |
283 | unsigned int pid = 0; | 277 | unsigned int pid = 0; |
284 | 278 | ||
285 | /* | 279 | /* |
286 | Minimal initialization to enable the I2C communication | 280 | Minimal initialization to enable the I2C communication |
287 | NOTE: do NOT change the values! | 281 | NOTE: do NOT change the values! |
288 | */ | 282 | */ |
289 | err += sn9c102_write_reg(cam, 0x01, 0x01); /* sensor power down */ | 283 | err = sn9c102_write_const_regs(cam, |
290 | err += sn9c102_write_reg(cam, 0x00, 0x01); /* sensor power on */ | 284 | {0x01, 0x01}, /* sensor power down */ |
291 | err += sn9c102_write_reg(cam, 0x28, 0x17); /* sensor clock at 24 MHz */ | 285 | {0x00, 0x01}, /* sensor power on */ |
286 | {0x28, 0x17});/* sensor clock 24 MHz */ | ||
292 | if (err) | 287 | if (err) |
293 | return -EIO; | 288 | return -EIO; |
294 | 289 | ||
diff --git a/drivers/media/video/sn9c102/sn9c102_pas202bcb.c b/drivers/media/video/sn9c102/sn9c102_pas202bcb.c index 7894f01b56e8..c1b8d6b63b47 100644 --- a/drivers/media/video/sn9c102/sn9c102_pas202bcb.c +++ b/drivers/media/video/sn9c102/sn9c102_pas202bcb.c | |||
@@ -28,9 +28,6 @@ | |||
28 | #include "sn9c102_sensor.h" | 28 | #include "sn9c102_sensor.h" |
29 | 29 | ||
30 | 30 | ||
31 | static struct sn9c102_sensor pas202bcb; | ||
32 | |||
33 | |||
34 | static int pas202bcb_init(struct sn9c102_device* cam) | 31 | static int pas202bcb_init(struct sn9c102_device* cam) |
35 | { | 32 | { |
36 | int err = 0; | 33 | int err = 0; |
@@ -38,47 +35,29 @@ static int pas202bcb_init(struct sn9c102_device* cam) | |||
38 | switch (sn9c102_get_bridge(cam)) { | 35 | switch (sn9c102_get_bridge(cam)) { |
39 | case BRIDGE_SN9C101: | 36 | case BRIDGE_SN9C101: |
40 | case BRIDGE_SN9C102: | 37 | case BRIDGE_SN9C102: |
41 | err += sn9c102_write_reg(cam, 0x00, 0x10); | 38 | err = sn9c102_write_const_regs(cam, {0x00, 0x10}, |
42 | err += sn9c102_write_reg(cam, 0x00, 0x11); | 39 | {0x00, 0x11}, {0x00, 0x14}, |
43 | err += sn9c102_write_reg(cam, 0x00, 0x14); | 40 | {0x20, 0x17}, {0x30, 0x19}, |
44 | err += sn9c102_write_reg(cam, 0x20, 0x17); | 41 | {0x09, 0x18}); |
45 | err += sn9c102_write_reg(cam, 0x30, 0x19); | ||
46 | err += sn9c102_write_reg(cam, 0x09, 0x18); | ||
47 | break; | 42 | break; |
48 | case BRIDGE_SN9C103: | 43 | case BRIDGE_SN9C103: |
49 | err += sn9c102_write_reg(cam, 0x00, 0x02); | 44 | err = sn9c102_write_const_regs(cam, {0x00, 0x02}, |
50 | err += sn9c102_write_reg(cam, 0x00, 0x03); | 45 | {0x00, 0x03}, {0x1a, 0x04}, |
51 | err += sn9c102_write_reg(cam, 0x1a, 0x04); | 46 | {0x20, 0x05}, {0x20, 0x06}, |
52 | err += sn9c102_write_reg(cam, 0x20, 0x05); | 47 | {0x20, 0x07}, {0x00, 0x10}, |
53 | err += sn9c102_write_reg(cam, 0x20, 0x06); | 48 | {0x00, 0x11}, {0x00, 0x14}, |
54 | err += sn9c102_write_reg(cam, 0x20, 0x07); | 49 | {0x20, 0x17}, {0x30, 0x19}, |
55 | err += sn9c102_write_reg(cam, 0x00, 0x10); | 50 | {0x09, 0x18}, {0x02, 0x1c}, |
56 | err += sn9c102_write_reg(cam, 0x00, 0x11); | 51 | {0x03, 0x1d}, {0x0f, 0x1e}, |
57 | err += sn9c102_write_reg(cam, 0x00, 0x14); | 52 | {0x0c, 0x1f}, {0x00, 0x20}, |
58 | err += sn9c102_write_reg(cam, 0x20, 0x17); | 53 | {0x10, 0x21}, {0x20, 0x22}, |
59 | err += sn9c102_write_reg(cam, 0x30, 0x19); | 54 | {0x30, 0x23}, {0x40, 0x24}, |
60 | err += sn9c102_write_reg(cam, 0x09, 0x18); | 55 | {0x50, 0x25}, {0x60, 0x26}, |
61 | err += sn9c102_write_reg(cam, 0x02, 0x1c); | 56 | {0x70, 0x27}, {0x80, 0x28}, |
62 | err += sn9c102_write_reg(cam, 0x03, 0x1d); | 57 | {0x90, 0x29}, {0xa0, 0x2a}, |
63 | err += sn9c102_write_reg(cam, 0x0f, 0x1e); | 58 | {0xb0, 0x2b}, {0xc0, 0x2c}, |
64 | err += sn9c102_write_reg(cam, 0x0c, 0x1f); | 59 | {0xd0, 0x2d}, {0xe0, 0x2e}, |
65 | err += sn9c102_write_reg(cam, 0x00, 0x20); | 60 | {0xf0, 0x2f}, {0xff, 0x30}); |
66 | err += sn9c102_write_reg(cam, 0x10, 0x21); | ||
67 | err += sn9c102_write_reg(cam, 0x20, 0x22); | ||
68 | err += sn9c102_write_reg(cam, 0x30, 0x23); | ||
69 | err += sn9c102_write_reg(cam, 0x40, 0x24); | ||
70 | err += sn9c102_write_reg(cam, 0x50, 0x25); | ||
71 | err += sn9c102_write_reg(cam, 0x60, 0x26); | ||
72 | err += sn9c102_write_reg(cam, 0x70, 0x27); | ||
73 | err += sn9c102_write_reg(cam, 0x80, 0x28); | ||
74 | err += sn9c102_write_reg(cam, 0x90, 0x29); | ||
75 | err += sn9c102_write_reg(cam, 0xa0, 0x2a); | ||
76 | err += sn9c102_write_reg(cam, 0xb0, 0x2b); | ||
77 | err += sn9c102_write_reg(cam, 0xc0, 0x2c); | ||
78 | err += sn9c102_write_reg(cam, 0xd0, 0x2d); | ||
79 | err += sn9c102_write_reg(cam, 0xe0, 0x2e); | ||
80 | err += sn9c102_write_reg(cam, 0xf0, 0x2f); | ||
81 | err += sn9c102_write_reg(cam, 0xff, 0x30); | ||
82 | break; | 61 | break; |
83 | default: | 62 | default: |
84 | break; | 63 | break; |
@@ -328,15 +307,15 @@ int sn9c102_probe_pas202bcb(struct sn9c102_device* cam) | |||
328 | switch (sn9c102_get_bridge(cam)) { | 307 | switch (sn9c102_get_bridge(cam)) { |
329 | case BRIDGE_SN9C101: | 308 | case BRIDGE_SN9C101: |
330 | case BRIDGE_SN9C102: | 309 | case BRIDGE_SN9C102: |
331 | err += sn9c102_write_reg(cam, 0x01, 0x01); /* power down */ | 310 | err = sn9c102_write_const_regs(cam, |
332 | err += sn9c102_write_reg(cam, 0x40, 0x01); /* power on */ | 311 | {0x01, 0x01}, /* power down */ |
333 | err += sn9c102_write_reg(cam, 0x28, 0x17); /* clock 24 MHz */ | 312 | {0x40, 0x01}, /* power on */ |
313 | {0x28, 0x17});/* clock 24 MHz */ | ||
334 | break; | 314 | break; |
335 | case BRIDGE_SN9C103: /* do _not_ change anything! */ | 315 | case BRIDGE_SN9C103: /* do _not_ change anything! */ |
336 | err += sn9c102_write_reg(cam, 0x09, 0x01); | 316 | err = sn9c102_write_const_regs(cam, {0x09, 0x01}, |
337 | err += sn9c102_write_reg(cam, 0x44, 0x01); | 317 | {0x44, 0x01}, {0x44, 0x02}, |
338 | err += sn9c102_write_reg(cam, 0x44, 0x02); | 318 | {0x29, 0x17}); |
339 | err += sn9c102_write_reg(cam, 0x29, 0x17); | ||
340 | break; | 319 | break; |
341 | default: | 320 | default: |
342 | break; | 321 | break; |
diff --git a/drivers/media/video/sn9c102/sn9c102_sensor.h b/drivers/media/video/sn9c102/sn9c102_sensor.h index 05f2942639c3..1bbf64c897a2 100644 --- a/drivers/media/video/sn9c102/sn9c102_sensor.h +++ b/drivers/media/video/sn9c102/sn9c102_sensor.h | |||
@@ -114,9 +114,17 @@ extern int sn9c102_i2c_write(struct sn9c102_device*, u8 address, u8 value); | |||
114 | extern int sn9c102_i2c_read(struct sn9c102_device*, u8 address); | 114 | extern int sn9c102_i2c_read(struct sn9c102_device*, u8 address); |
115 | 115 | ||
116 | /* I/O on registers in the bridge. Could be used by the sensor methods too */ | 116 | /* I/O on registers in the bridge. Could be used by the sensor methods too */ |
117 | extern int sn9c102_write_regs(struct sn9c102_device*, u8* buff, u16 index); | ||
118 | extern int sn9c102_write_reg(struct sn9c102_device*, u8 value, u16 index); | ||
119 | extern int sn9c102_pread_reg(struct sn9c102_device*, u16 index); | 117 | extern int sn9c102_pread_reg(struct sn9c102_device*, u16 index); |
118 | extern int sn9c102_write_reg(struct sn9c102_device*, u8 value, u16 index); | ||
119 | extern int sn9c102_write_regs(struct sn9c102_device*, const u8 valreg[][2], | ||
120 | int count); | ||
121 | /* | ||
122 | * Write multiple registers with constant values. For example: | ||
123 | * sn9c102_write_const_regs(cam, {0x00, 0x14}, {0x60, 0x17}, {0x0f, 0x18}); | ||
124 | */ | ||
125 | #define sn9c102_write_const_regs(device, data...) \ | ||
126 | ({ const static u8 _data[][2] = {data}; \ | ||
127 | sn9c102_write_regs(device, _data, ARRAY_SIZE(_data)); }) | ||
120 | 128 | ||
121 | /*****************************************************************************/ | 129 | /*****************************************************************************/ |
122 | 130 | ||
diff --git a/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c b/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c index 90023ad63adc..0e7ec8662c70 100644 --- a/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c +++ b/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c | |||
@@ -22,21 +22,14 @@ | |||
22 | #include "sn9c102_sensor.h" | 22 | #include "sn9c102_sensor.h" |
23 | 23 | ||
24 | 24 | ||
25 | static struct sn9c102_sensor tas5110c1b; | ||
26 | |||
27 | |||
28 | static int tas5110c1b_init(struct sn9c102_device* cam) | 25 | static int tas5110c1b_init(struct sn9c102_device* cam) |
29 | { | 26 | { |
30 | int err = 0; | 27 | int err = 0; |
31 | 28 | ||
32 | err += sn9c102_write_reg(cam, 0x01, 0x01); | 29 | err = sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x44, 0x01}, |
33 | err += sn9c102_write_reg(cam, 0x44, 0x01); | 30 | {0x00, 0x10}, {0x00, 0x11}, |
34 | err += sn9c102_write_reg(cam, 0x00, 0x10); | 31 | {0x0a, 0x14}, {0x60, 0x17}, |
35 | err += sn9c102_write_reg(cam, 0x00, 0x11); | 32 | {0x06, 0x18}, {0xfb, 0x19}); |
36 | err += sn9c102_write_reg(cam, 0x0a, 0x14); | ||
37 | err += sn9c102_write_reg(cam, 0x60, 0x17); | ||
38 | err += sn9c102_write_reg(cam, 0x06, 0x18); | ||
39 | err += sn9c102_write_reg(cam, 0xfb, 0x19); | ||
40 | 33 | ||
41 | err += sn9c102_i2c_write(cam, 0xc0, 0x80); | 34 | err += sn9c102_i2c_write(cam, 0xc0, 0x80); |
42 | 35 | ||
@@ -98,7 +91,7 @@ static int tas5110c1b_set_pix_format(struct sn9c102_device* cam, | |||
98 | static struct sn9c102_sensor tas5110c1b = { | 91 | static struct sn9c102_sensor tas5110c1b = { |
99 | .name = "TAS5110C1B", | 92 | .name = "TAS5110C1B", |
100 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", | 93 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", |
101 | .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103, | 94 | .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102, |
102 | .sysfs_ops = SN9C102_I2C_WRITE, | 95 | .sysfs_ops = SN9C102_I2C_WRITE, |
103 | .frequency = SN9C102_I2C_100KHZ, | 96 | .frequency = SN9C102_I2C_100KHZ, |
104 | .interface = SN9C102_I2C_3WIRES, | 97 | .interface = SN9C102_I2C_3WIRES, |
@@ -146,7 +139,6 @@ int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam) | |||
146 | const struct usb_device_id tas5110c1b_id_table[] = { | 139 | const struct usb_device_id tas5110c1b_id_table[] = { |
147 | { USB_DEVICE(0x0c45, 0x6001), }, | 140 | { USB_DEVICE(0x0c45, 0x6001), }, |
148 | { USB_DEVICE(0x0c45, 0x6005), }, | 141 | { USB_DEVICE(0x0c45, 0x6005), }, |
149 | { USB_DEVICE(0x0c45, 0x6007), }, | ||
150 | { USB_DEVICE(0x0c45, 0x60ab), }, | 142 | { USB_DEVICE(0x0c45, 0x60ab), }, |
151 | { } | 143 | { } |
152 | }; | 144 | }; |
diff --git a/drivers/media/video/sn9c102/sn9c102_tas5110d.c b/drivers/media/video/sn9c102/sn9c102_tas5110d.c new file mode 100644 index 000000000000..83a39e8b5e71 --- /dev/null +++ b/drivers/media/video/sn9c102/sn9c102_tas5110d.c | |||
@@ -0,0 +1,118 @@ | |||
1 | /*************************************************************************** | ||
2 | * Plug-in for TAS5110D image sensor connected to the SN9C1xx PC Camera * | ||
3 | * Controllers * | ||
4 | * * | ||
5 | * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it> * | ||
6 | * * | ||
7 | * This program is free software; you can redistribute it and/or modify * | ||
8 | * it under the terms of the GNU General Public License as published by * | ||
9 | * the Free Software Foundation; either version 2 of the License, or * | ||
10 | * (at your option) any later version. * | ||
11 | * * | ||
12 | * This program is distributed in the hope that it will be useful, * | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
15 | * GNU General Public License for more details. * | ||
16 | * * | ||
17 | * You should have received a copy of the GNU General Public License * | ||
18 | * along with this program; if not, write to the Free Software * | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * | ||
20 | ***************************************************************************/ | ||
21 | |||
22 | #include "sn9c102_sensor.h" | ||
23 | |||
24 | |||
25 | static int tas5110d_init(struct sn9c102_device* cam) | ||
26 | { | ||
27 | int err; | ||
28 | |||
29 | err = sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x04, 0x01}, | ||
30 | {0x0a, 0x14}, {0x60, 0x17}, | ||
31 | {0x06, 0x18}, {0xfb, 0x19}); | ||
32 | |||
33 | err += sn9c102_i2c_write(cam, 0x9a, 0xca); | ||
34 | |||
35 | return err; | ||
36 | } | ||
37 | |||
38 | |||
39 | static int tas5110d_set_crop(struct sn9c102_device* cam, | ||
40 | const struct v4l2_rect* rect) | ||
41 | { | ||
42 | struct sn9c102_sensor* s = sn9c102_get_sensor(cam); | ||
43 | int err = 0; | ||
44 | u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 69, | ||
45 | v_start = (u8)(rect->top - s->cropcap.bounds.top) + 9; | ||
46 | |||
47 | err += sn9c102_write_reg(cam, h_start, 0x12); | ||
48 | err += sn9c102_write_reg(cam, v_start, 0x13); | ||
49 | |||
50 | err += sn9c102_write_reg(cam, 0x14, 0x1a); | ||
51 | err += sn9c102_write_reg(cam, 0x0a, 0x1b); | ||
52 | |||
53 | return err; | ||
54 | } | ||
55 | |||
56 | |||
57 | static int tas5110d_set_pix_format(struct sn9c102_device* cam, | ||
58 | const struct v4l2_pix_format* pix) | ||
59 | { | ||
60 | int err = 0; | ||
61 | |||
62 | if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) | ||
63 | err += sn9c102_write_reg(cam, 0x3b, 0x19); | ||
64 | else | ||
65 | err += sn9c102_write_reg(cam, 0xfb, 0x19); | ||
66 | |||
67 | return err; | ||
68 | } | ||
69 | |||
70 | |||
71 | static struct sn9c102_sensor tas5110d = { | ||
72 | .name = "TAS5110D", | ||
73 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", | ||
74 | .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102, | ||
75 | .sysfs_ops = SN9C102_I2C_WRITE, | ||
76 | .frequency = SN9C102_I2C_100KHZ, | ||
77 | .interface = SN9C102_I2C_2WIRES, | ||
78 | .i2c_slave_id = 0x61, | ||
79 | .init = &tas5110d_init, | ||
80 | .cropcap = { | ||
81 | .bounds = { | ||
82 | .left = 0, | ||
83 | .top = 0, | ||
84 | .width = 352, | ||
85 | .height = 288, | ||
86 | }, | ||
87 | .defrect = { | ||
88 | .left = 0, | ||
89 | .top = 0, | ||
90 | .width = 352, | ||
91 | .height = 288, | ||
92 | }, | ||
93 | }, | ||
94 | .set_crop = &tas5110d_set_crop, | ||
95 | .pix_format = { | ||
96 | .width = 352, | ||
97 | .height = 288, | ||
98 | .pixelformat = V4L2_PIX_FMT_SBGGR8, | ||
99 | .priv = 8, | ||
100 | }, | ||
101 | .set_pix_format = &tas5110d_set_pix_format | ||
102 | }; | ||
103 | |||
104 | |||
105 | int sn9c102_probe_tas5110d(struct sn9c102_device* cam) | ||
106 | { | ||
107 | const struct usb_device_id tas5110d_id_table[] = { | ||
108 | { USB_DEVICE(0x0c45, 0x6007), }, | ||
109 | { } | ||
110 | }; | ||
111 | |||
112 | if (!sn9c102_match_id(cam, tas5110d_id_table)) | ||
113 | return -ENODEV; | ||
114 | |||
115 | sn9c102_attach_sensor(cam, &tas5110d); | ||
116 | |||
117 | return 0; | ||
118 | } | ||
diff --git a/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c b/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c index cb1b318bc1ff..50406503fc40 100644 --- a/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c +++ b/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c | |||
@@ -22,21 +22,14 @@ | |||
22 | #include "sn9c102_sensor.h" | 22 | #include "sn9c102_sensor.h" |
23 | 23 | ||
24 | 24 | ||
25 | static struct sn9c102_sensor tas5130d1b; | ||
26 | |||
27 | |||
28 | static int tas5130d1b_init(struct sn9c102_device* cam) | 25 | static int tas5130d1b_init(struct sn9c102_device* cam) |
29 | { | 26 | { |
30 | int err = 0; | 27 | int err; |
31 | 28 | ||
32 | err += sn9c102_write_reg(cam, 0x01, 0x01); | 29 | err = sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x20, 0x17}, |
33 | err += sn9c102_write_reg(cam, 0x20, 0x17); | 30 | {0x04, 0x01}, {0x01, 0x10}, |
34 | err += sn9c102_write_reg(cam, 0x04, 0x01); | 31 | {0x00, 0x11}, {0x00, 0x14}, |
35 | err += sn9c102_write_reg(cam, 0x01, 0x10); | 32 | {0x60, 0x17}, {0x07, 0x18}); |
36 | err += sn9c102_write_reg(cam, 0x00, 0x11); | ||
37 | err += sn9c102_write_reg(cam, 0x00, 0x14); | ||
38 | err += sn9c102_write_reg(cam, 0x60, 0x17); | ||
39 | err += sn9c102_write_reg(cam, 0x07, 0x18); | ||
40 | 33 | ||
41 | return err; | 34 | return err; |
42 | } | 35 | } |
@@ -99,7 +92,7 @@ static int tas5130d1b_set_pix_format(struct sn9c102_device* cam, | |||
99 | static struct sn9c102_sensor tas5130d1b = { | 92 | static struct sn9c102_sensor tas5130d1b = { |
100 | .name = "TAS5130D1B", | 93 | .name = "TAS5130D1B", |
101 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", | 94 | .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", |
102 | .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103, | 95 | .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102, |
103 | .sysfs_ops = SN9C102_I2C_WRITE, | 96 | .sysfs_ops = SN9C102_I2C_WRITE, |
104 | .frequency = SN9C102_I2C_100KHZ, | 97 | .frequency = SN9C102_I2C_100KHZ, |
105 | .interface = SN9C102_I2C_3WIRES, | 98 | .interface = SN9C102_I2C_3WIRES, |
diff --git a/drivers/media/video/tda7432.c b/drivers/media/video/tda7432.c index d1ccc064206f..43225802a551 100644 --- a/drivers/media/video/tda7432.c +++ b/drivers/media/video/tda7432.c | |||
@@ -45,7 +45,6 @@ | |||
45 | #include <linux/slab.h> | 45 | #include <linux/slab.h> |
46 | #include <linux/videodev.h> | 46 | #include <linux/videodev.h> |
47 | #include <linux/i2c.h> | 47 | #include <linux/i2c.h> |
48 | #include <linux/i2c-algo-bit.h> | ||
49 | 48 | ||
50 | #include <media/v4l2-common.h> | 49 | #include <media/v4l2-common.h> |
51 | #include <media/i2c-addr.h> | 50 | #include <media/i2c-addr.h> |
diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index 027c8a074dfe..1a1bef0e9c3d 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c | |||
@@ -192,14 +192,52 @@ static struct tda827xa_data tda827xa_analog[] = { | |||
192 | { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0} /* End */ | 192 | { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0} /* End */ |
193 | }; | 193 | }; |
194 | 194 | ||
195 | static void tda827xa_lna_gain(struct i2c_client *c, int high) | ||
196 | { | ||
197 | struct tuner *t = i2c_get_clientdata(c); | ||
198 | unsigned char buf[] = {0x22, 0x01}; | ||
199 | int arg; | ||
200 | struct i2c_msg msg = {.addr = c->addr, .flags = 0, .buf = buf, .len = sizeof(buf)}; | ||
201 | if (t->config) { | ||
202 | if (high) | ||
203 | tuner_dbg("setting LNA to high gain\n"); | ||
204 | else | ||
205 | tuner_dbg("setting LNA to low gain\n"); | ||
206 | } | ||
207 | switch (t->config) { | ||
208 | case 0: /* no LNA */ | ||
209 | break; | ||
210 | case 1: /* switch is GPIO 0 of tda8290 */ | ||
211 | case 2: | ||
212 | /* turn Vsync on */ | ||
213 | if (t->std & V4L2_STD_MN) | ||
214 | arg = 1; | ||
215 | else | ||
216 | arg = 0; | ||
217 | if (t->tuner_callback) | ||
218 | t->tuner_callback(c->adapter->algo_data, 1, arg); | ||
219 | buf[1] = high ? 0 : 1; | ||
220 | if (t->config == 2) | ||
221 | buf[1] = high ? 1 : 0; | ||
222 | i2c_transfer(c->adapter, &msg, 1); | ||
223 | break; | ||
224 | case 3: /* switch with GPIO of saa713x */ | ||
225 | if (t->tuner_callback) | ||
226 | t->tuner_callback(c->adapter->algo_data, 0, high); | ||
227 | break; | ||
228 | } | ||
229 | } | ||
230 | |||
195 | static void tda827xa_tune(struct i2c_client *c, u16 ifc, unsigned int freq) | 231 | static void tda827xa_tune(struct i2c_client *c, u16 ifc, unsigned int freq) |
196 | { | 232 | { |
197 | unsigned char tuner_reg[14]; | 233 | unsigned char tuner_reg[11]; |
198 | unsigned char reg2[2]; | ||
199 | u32 N; | 234 | u32 N; |
200 | int i; | 235 | int i; |
201 | struct tuner *t = i2c_get_clientdata(c); | 236 | struct tuner *t = i2c_get_clientdata(c); |
202 | struct i2c_msg msg = {.addr = t->tda827x_addr, .flags = 0}; | 237 | struct i2c_msg msg = {.addr = t->tda827x_addr, .flags = 0, .buf = tuner_reg}; |
238 | |||
239 | tda827xa_lna_gain( c, 1); | ||
240 | msleep(10); | ||
203 | 241 | ||
204 | if (t->mode == V4L2_TUNER_RADIO) | 242 | if (t->mode == V4L2_TUNER_RADIO) |
205 | freq = freq / 1000; | 243 | freq = freq / 1000; |
@@ -222,48 +260,58 @@ static void tda827xa_tune(struct i2c_client *c, u16 ifc, unsigned int freq) | |||
222 | tuner_reg[5] = (tda827xa_analog[i].spd << 5) + (tda827xa_analog[i].svco << 3) + | 260 | tuner_reg[5] = (tda827xa_analog[i].spd << 5) + (tda827xa_analog[i].svco << 3) + |
223 | tda827xa_analog[i].sbs; | 261 | tda827xa_analog[i].sbs; |
224 | tuner_reg[6] = 0x8b + (tda827xa_analog[i].gc3 << 4); | 262 | tuner_reg[6] = 0x8b + (tda827xa_analog[i].gc3 << 4); |
225 | tuner_reg[7] = 0x0c; | 263 | tuner_reg[7] = 0x1c; |
226 | tuner_reg[8] = 4; | 264 | tuner_reg[8] = 4; |
227 | tuner_reg[9] = 0x20; | 265 | tuner_reg[9] = 0x20; |
228 | tuner_reg[10] = 0xff; | 266 | tuner_reg[10] = 0x00; |
229 | tuner_reg[11] = 0xe0; | 267 | msg.len = 11; |
230 | tuner_reg[12] = 0; | 268 | i2c_transfer(c->adapter, &msg, 1); |
231 | tuner_reg[13] = 0x39 + (t->tda827x_lpsel << 1); | ||
232 | 269 | ||
233 | msg.buf = tuner_reg; | 270 | tuner_reg[0] = 0x90; |
234 | msg.len = 14; | 271 | tuner_reg[1] = 0xff; |
272 | tuner_reg[2] = 0xe0; | ||
273 | tuner_reg[3] = 0; | ||
274 | tuner_reg[4] = 0x99 + (t->tda827x_lpsel << 1); | ||
275 | msg.len = 5; | ||
235 | i2c_transfer(c->adapter, &msg, 1); | 276 | i2c_transfer(c->adapter, &msg, 1); |
236 | 277 | ||
237 | msg.buf= reg2; | 278 | tuner_reg[0] = 0xa0; |
279 | tuner_reg[1] = 0xc0; | ||
238 | msg.len = 2; | 280 | msg.len = 2; |
239 | reg2[0] = 0x60; | ||
240 | reg2[1] = 0x3c; | ||
241 | i2c_transfer(c->adapter, &msg, 1); | 281 | i2c_transfer(c->adapter, &msg, 1); |
242 | 282 | ||
243 | reg2[0] = 0xa0; | 283 | tuner_reg[0] = 0x30; |
244 | reg2[1] = 0xc0; | 284 | tuner_reg[1] = 0x10 + tda827xa_analog[i].scr; |
245 | i2c_transfer(c->adapter, &msg, 1); | 285 | i2c_transfer(c->adapter, &msg, 1); |
246 | 286 | ||
247 | msleep(2); | 287 | msg.flags = I2C_M_RD; |
248 | reg2[0] = 0x30; | 288 | i2c_transfer(c->adapter, &msg, 1); |
249 | reg2[1] = 0x10 + tda827xa_analog[i].scr; | 289 | msg.flags = 0; |
290 | tuner_reg[1] >>= 4; | ||
291 | tuner_dbg("AGC2 gain is: %d\n", tuner_reg[1]); | ||
292 | if (tuner_reg[1] < 1) | ||
293 | tda827xa_lna_gain( c, 0); | ||
294 | |||
295 | msleep(100); | ||
296 | tuner_reg[0] = 0x60; | ||
297 | tuner_reg[1] = 0x3c; | ||
250 | i2c_transfer(c->adapter, &msg, 1); | 298 | i2c_transfer(c->adapter, &msg, 1); |
251 | 299 | ||
252 | msleep(550); | 300 | msleep(163); |
253 | reg2[0] = 0x50; | 301 | tuner_reg[0] = 0x50; |
254 | reg2[1] = 0x8f + (tda827xa_analog[i].gc3 << 4); | 302 | tuner_reg[1] = 0x8f + (tda827xa_analog[i].gc3 << 4); |
255 | i2c_transfer(c->adapter, &msg, 1); | 303 | i2c_transfer(c->adapter, &msg, 1); |
256 | 304 | ||
257 | reg2[0] = 0x80; | 305 | tuner_reg[0] = 0x80; |
258 | reg2[1] = 0x28; | 306 | tuner_reg[1] = 0x28; |
259 | i2c_transfer(c->adapter, &msg, 1); | 307 | i2c_transfer(c->adapter, &msg, 1); |
260 | 308 | ||
261 | reg2[0] = 0xb0; | 309 | tuner_reg[0] = 0xb0; |
262 | reg2[1] = 0x01; | 310 | tuner_reg[1] = 0x01; |
263 | i2c_transfer(c->adapter, &msg, 1); | 311 | i2c_transfer(c->adapter, &msg, 1); |
264 | 312 | ||
265 | reg2[0] = 0xc0; | 313 | tuner_reg[0] = 0xc0; |
266 | reg2[1] = 0x19 + (t->tda827x_lpsel << 1); | 314 | tuner_reg[1] = 0x19 + (t->tda827x_lpsel << 1); |
267 | i2c_transfer(c->adapter, &msg, 1); | 315 | i2c_transfer(c->adapter, &msg, 1); |
268 | } | 316 | } |
269 | 317 | ||
@@ -319,7 +367,9 @@ static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq) | |||
319 | unsigned char addr_pll_stat = 0x1b; | 367 | unsigned char addr_pll_stat = 0x1b; |
320 | unsigned char adc_sat, agc_stat, | 368 | unsigned char adc_sat, agc_stat, |
321 | pll_stat; | 369 | pll_stat; |
370 | int i; | ||
322 | 371 | ||
372 | tuner_dbg("tda827xa config is 0x%02x\n", t->config); | ||
323 | i2c_master_send(c, easy_mode, 2); | 373 | i2c_master_send(c, easy_mode, 2); |
324 | i2c_master_send(c, agc_out_on, 2); | 374 | i2c_master_send(c, agc_out_on, 2); |
325 | i2c_master_send(c, soft_reset, 2); | 375 | i2c_master_send(c, soft_reset, 2); |
@@ -340,17 +390,22 @@ static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq) | |||
340 | tda827xa_tune(c, ifc, freq); | 390 | tda827xa_tune(c, ifc, freq); |
341 | else | 391 | else |
342 | tda827x_tune(c, ifc, freq); | 392 | tda827x_tune(c, ifc, freq); |
393 | for (i = 0; i < 3; i++) { | ||
394 | i2c_master_send(c, &addr_pll_stat, 1); | ||
395 | i2c_master_recv(c, &pll_stat, 1); | ||
396 | if (pll_stat & 0x80) { | ||
397 | i2c_master_send(c, &addr_adc_sat, 1); | ||
398 | i2c_master_recv(c, &adc_sat, 1); | ||
399 | i2c_master_send(c, &addr_agc_stat, 1); | ||
400 | i2c_master_recv(c, &agc_stat, 1); | ||
401 | tuner_dbg("tda8290 is locked, AGC: %d\n", agc_stat); | ||
402 | break; | ||
403 | } else { | ||
404 | tuner_dbg("tda8290 not locked, no signal?\n"); | ||
405 | msleep(100); | ||
406 | } | ||
407 | } | ||
343 | /* adjust headroom resp. gain */ | 408 | /* adjust headroom resp. gain */ |
344 | i2c_master_send(c, &addr_adc_sat, 1); | ||
345 | i2c_master_recv(c, &adc_sat, 1); | ||
346 | i2c_master_send(c, &addr_agc_stat, 1); | ||
347 | i2c_master_recv(c, &agc_stat, 1); | ||
348 | i2c_master_send(c, &addr_pll_stat, 1); | ||
349 | i2c_master_recv(c, &pll_stat, 1); | ||
350 | if (pll_stat & 0x80) | ||
351 | tuner_dbg("tda8290 is locked, AGC: %d\n", agc_stat); | ||
352 | else | ||
353 | tuner_dbg("tda8290 not locked, no signal?\n"); | ||
354 | if ((agc_stat > 115) || (!(pll_stat & 0x80) && (adc_sat < 20))) { | 409 | if ((agc_stat > 115) || (!(pll_stat & 0x80) && (adc_sat < 20))) { |
355 | tuner_dbg("adjust gain, step 1. Agc: %d, ADC stat: %d, lock: %d\n", | 410 | tuner_dbg("adjust gain, step 1. Agc: %d, ADC stat: %d, lock: %d\n", |
356 | agc_stat, adc_sat, pll_stat & 0x80); | 411 | agc_stat, adc_sat, pll_stat & 0x80); |
@@ -407,7 +462,6 @@ static void set_audio(struct tuner *t) | |||
407 | char* mode; | 462 | char* mode; |
408 | 463 | ||
409 | t->tda827x_lpsel = 0; | 464 | t->tda827x_lpsel = 0; |
410 | mode = "xx"; | ||
411 | if (t->std & V4L2_STD_MN) { | 465 | if (t->std & V4L2_STD_MN) { |
412 | t->sgIF = 92; | 466 | t->sgIF = 92; |
413 | t->tda8290_easy_mode = 0x01; | 467 | t->tda8290_easy_mode = 0x01; |
@@ -437,8 +491,12 @@ static void set_audio(struct tuner *t) | |||
437 | t->sgIF = 20; | 491 | t->sgIF = 20; |
438 | t->tda8290_easy_mode = 0x40; | 492 | t->tda8290_easy_mode = 0x40; |
439 | mode = "LC"; | 493 | mode = "LC"; |
494 | } else { | ||
495 | t->sgIF = 124; | ||
496 | t->tda8290_easy_mode = 0x10; | ||
497 | mode = "xx"; | ||
440 | } | 498 | } |
441 | tuner_dbg("setting tda8290 to system %s\n", mode); | 499 | tuner_dbg("setting tda8290 to system %s\n", mode); |
442 | } | 500 | } |
443 | 501 | ||
444 | static void set_tv_freq(struct i2c_client *c, unsigned int freq) | 502 | static void set_tv_freq(struct i2c_client *c, unsigned int freq) |
@@ -487,11 +545,16 @@ static void standby(struct i2c_client *c) | |||
487 | 545 | ||
488 | static void tda8290_init_if(struct i2c_client *c) | 546 | static void tda8290_init_if(struct i2c_client *c) |
489 | { | 547 | { |
548 | struct tuner *t = i2c_get_clientdata(c); | ||
490 | unsigned char set_VS[] = { 0x30, 0x6F }; | 549 | unsigned char set_VS[] = { 0x30, 0x6F }; |
550 | unsigned char set_GP00_CF[] = { 0x20, 0x01 }; | ||
491 | unsigned char set_GP01_CF[] = { 0x20, 0x0B }; | 551 | unsigned char set_GP01_CF[] = { 0x20, 0x0B }; |
492 | 552 | ||
553 | if ((t->config == 1) || (t->config == 2)) | ||
554 | i2c_master_send(c, set_GP00_CF, 2); | ||
555 | else | ||
556 | i2c_master_send(c, set_GP01_CF, 2); | ||
493 | i2c_master_send(c, set_VS, 2); | 557 | i2c_master_send(c, set_VS, 2); |
494 | i2c_master_send(c, set_GP01_CF, 2); | ||
495 | } | 558 | } |
496 | 559 | ||
497 | static void tda8290_init_tuner(struct i2c_client *c) | 560 | static void tda8290_init_tuner(struct i2c_client *c) |
@@ -576,6 +639,7 @@ int tda8290_init(struct i2c_client *c) | |||
576 | t->has_signal = has_signal; | 639 | t->has_signal = has_signal; |
577 | t->standby = standby; | 640 | t->standby = standby; |
578 | t->tda827x_lpsel = 0; | 641 | t->tda827x_lpsel = 0; |
642 | t->mode = V4L2_TUNER_ANALOG_TV; | ||
579 | 643 | ||
580 | tda8290_init_tuner(c); | 644 | tda8290_init_tuner(c); |
581 | tda8290_init_if(c); | 645 | tda8290_init_if(c); |
diff --git a/drivers/media/video/tda9875.c b/drivers/media/video/tda9875.c index 00f0e8b6e03b..d11044170872 100644 --- a/drivers/media/video/tda9875.c +++ b/drivers/media/video/tda9875.c | |||
@@ -27,7 +27,6 @@ | |||
27 | #include <linux/videodev.h> | 27 | #include <linux/videodev.h> |
28 | #include <media/v4l2-common.h> | 28 | #include <media/v4l2-common.h> |
29 | #include <linux/i2c.h> | 29 | #include <linux/i2c.h> |
30 | #include <linux/i2c-algo-bit.h> | ||
31 | #include <linux/init.h> | 30 | #include <linux/init.h> |
32 | 31 | ||
33 | 32 | ||
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 15dbc6bf42a7..505591a7abe9 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c | |||
@@ -144,7 +144,8 @@ static void set_freq(struct i2c_client *c, unsigned long freq) | |||
144 | } | 144 | } |
145 | 145 | ||
146 | static void set_type(struct i2c_client *c, unsigned int type, | 146 | static void set_type(struct i2c_client *c, unsigned int type, |
147 | unsigned int new_mode_mask) | 147 | unsigned int new_mode_mask, unsigned int new_config, |
148 | int (*tuner_callback) (void *dev, int command,int arg)) | ||
148 | { | 149 | { |
149 | struct tuner *t = i2c_get_clientdata(c); | 150 | struct tuner *t = i2c_get_clientdata(c); |
150 | unsigned char buffer[4]; | 151 | unsigned char buffer[4]; |
@@ -159,15 +160,20 @@ static void set_type(struct i2c_client *c, unsigned int type, | |||
159 | return; | 160 | return; |
160 | } | 161 | } |
161 | 162 | ||
163 | t->type = type; | ||
164 | t->config = new_config; | ||
165 | if (tuner_callback != NULL) { | ||
166 | tuner_dbg("defining GPIO callback\n"); | ||
167 | t->tuner_callback = tuner_callback; | ||
168 | } | ||
169 | |||
162 | /* This code detects calls by card attach_inform */ | 170 | /* This code detects calls by card attach_inform */ |
163 | if (NULL == t->i2c.dev.driver) { | 171 | if (NULL == t->i2c.dev.driver) { |
164 | tuner_dbg ("tuner 0x%02x: called during i2c_client register by adapter's attach_inform\n", c->addr); | 172 | tuner_dbg ("tuner 0x%02x: called during i2c_client register by adapter's attach_inform\n", c->addr); |
165 | 173 | ||
166 | t->type=type; | ||
167 | return; | 174 | return; |
168 | } | 175 | } |
169 | 176 | ||
170 | t->type = type; | ||
171 | switch (t->type) { | 177 | switch (t->type) { |
172 | case TUNER_MT2032: | 178 | case TUNER_MT2032: |
173 | microtune_init(c); | 179 | microtune_init(c); |
@@ -234,10 +240,11 @@ static void set_addr(struct i2c_client *c, struct tuner_setup *tun_setup) | |||
234 | 240 | ||
235 | tuner_dbg("set addr for type %i\n", t->type); | 241 | tuner_dbg("set addr for type %i\n", t->type); |
236 | 242 | ||
237 | if ( t->type == UNSET && ((tun_setup->addr == ADDR_UNSET && | 243 | if ( (t->type == UNSET && ((tun_setup->addr == ADDR_UNSET) && |
238 | (t->mode_mask & tun_setup->mode_mask)) || | 244 | (t->mode_mask & tun_setup->mode_mask))) || |
239 | tun_setup->addr == c->addr)) { | 245 | (tun_setup->addr == c->addr)) { |
240 | set_type(c, tun_setup->type, tun_setup->mode_mask); | 246 | set_type(c, tun_setup->type, tun_setup->mode_mask, |
247 | tun_setup->config, tun_setup->tuner_callback); | ||
241 | } | 248 | } |
242 | } | 249 | } |
243 | 250 | ||
@@ -496,7 +503,7 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) | |||
496 | register_client: | 503 | register_client: |
497 | tuner_info("chip found @ 0x%x (%s)\n", addr << 1, adap->name); | 504 | tuner_info("chip found @ 0x%x (%s)\n", addr << 1, adap->name); |
498 | i2c_attach_client (&t->i2c); | 505 | i2c_attach_client (&t->i2c); |
499 | set_type (&t->i2c,t->type, t->mode_mask); | 506 | set_type (&t->i2c,t->type, t->mode_mask, t->config, t->tuner_callback); |
500 | return 0; | 507 | return 0; |
501 | } | 508 | } |
502 | 509 | ||
@@ -576,10 +583,11 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) | |||
576 | switch (cmd) { | 583 | switch (cmd) { |
577 | /* --- configuration --- */ | 584 | /* --- configuration --- */ |
578 | case TUNER_SET_TYPE_ADDR: | 585 | case TUNER_SET_TYPE_ADDR: |
579 | tuner_dbg ("Calling set_type_addr for type=%d, addr=0x%02x, mode=0x%02x\n", | 586 | tuner_dbg ("Calling set_type_addr for type=%d, addr=0x%02x, mode=0x%02x, config=0x%02x\n", |
580 | ((struct tuner_setup *)arg)->type, | 587 | ((struct tuner_setup *)arg)->type, |
581 | ((struct tuner_setup *)arg)->addr, | 588 | ((struct tuner_setup *)arg)->addr, |
582 | ((struct tuner_setup *)arg)->mode_mask); | 589 | ((struct tuner_setup *)arg)->mode_mask, |
590 | ((struct tuner_setup *)arg)->config); | ||
583 | 591 | ||
584 | set_addr(client, (struct tuner_setup *)arg); | 592 | set_addr(client, (struct tuner_setup *)arg); |
585 | break; | 593 | break; |
diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c index d506dfaa45a9..a2da5d2affff 100644 --- a/drivers/media/video/tvaudio.c +++ b/drivers/media/video/tvaudio.c | |||
@@ -25,7 +25,6 @@ | |||
25 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
26 | #include <linux/videodev.h> | 26 | #include <linux/videodev.h> |
27 | #include <linux/i2c.h> | 27 | #include <linux/i2c.h> |
28 | #include <linux/i2c-algo-bit.h> | ||
29 | #include <linux/init.h> | 28 | #include <linux/init.h> |
30 | #include <linux/smp_lock.h> | 29 | #include <linux/smp_lock.h> |
31 | #include <linux/kthread.h> | 30 | #include <linux/kthread.h> |
@@ -33,6 +32,7 @@ | |||
33 | 32 | ||
34 | #include <media/tvaudio.h> | 33 | #include <media/tvaudio.h> |
35 | #include <media/v4l2-common.h> | 34 | #include <media/v4l2-common.h> |
35 | #include <media/v4l2-chip-ident.h> | ||
36 | 36 | ||
37 | #include <media/i2c-addr.h> | 37 | #include <media/i2c-addr.h> |
38 | 38 | ||
@@ -1775,6 +1775,9 @@ static int chip_command(struct i2c_client *client, | |||
1775 | /* the thread will call checkmode() later */ | 1775 | /* the thread will call checkmode() later */ |
1776 | } | 1776 | } |
1777 | break; | 1777 | break; |
1778 | |||
1779 | case VIDIOC_G_CHIP_IDENT: | ||
1780 | return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_TVAUDIO, 0); | ||
1778 | } | 1781 | } |
1779 | return 0; | 1782 | return 0; |
1780 | } | 1783 | } |
diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c index 4e7c1fa668d3..a1136da74ba8 100644 --- a/drivers/media/video/tveeprom.c +++ b/drivers/media/video/tveeprom.c | |||
@@ -163,7 +163,7 @@ hauppauge_tuner[] = | |||
163 | /* 60-69 */ | 163 | /* 60-69 */ |
164 | { TUNER_PHILIPS_FM1216ME_MK3, "LG S001D MK3"}, | 164 | { TUNER_PHILIPS_FM1216ME_MK3, "LG S001D MK3"}, |
165 | { TUNER_ABSENT, "LG M001D MK3"}, | 165 | { TUNER_ABSENT, "LG M001D MK3"}, |
166 | { TUNER_ABSENT, "LG S701D MK3"}, | 166 | { TUNER_PHILIPS_FM1216ME_MK3, "LG S701D MK3"}, |
167 | { TUNER_ABSENT, "LG M701D MK3"}, | 167 | { TUNER_ABSENT, "LG M701D MK3"}, |
168 | { TUNER_ABSENT, "Temic 4146FM5"}, | 168 | { TUNER_ABSENT, "Temic 4146FM5"}, |
169 | { TUNER_ABSENT, "Temic 4136FY5"}, | 169 | { TUNER_ABSENT, "Temic 4136FY5"}, |
@@ -229,6 +229,36 @@ hauppauge_tuner[] = | |||
229 | /* 120-129 */ | 229 | /* 120-129 */ |
230 | { TUNER_ABSENT, "Xceive XC3028"}, | 230 | { TUNER_ABSENT, "Xceive XC3028"}, |
231 | { TUNER_ABSENT, "Philips FQ1216LME MK5"}, | 231 | { TUNER_ABSENT, "Philips FQ1216LME MK5"}, |
232 | { TUNER_ABSENT, "Philips FQD1216LME"}, | ||
233 | { TUNER_ABSENT, "Conexant CX24118A"}, | ||
234 | { TUNER_ABSENT, "TCL DMF11WIP"}, | ||
235 | { TUNER_ABSENT, "TCL MFNM05_4H_E"}, | ||
236 | { TUNER_ABSENT, "TCL MNM05_4H_E"}, | ||
237 | { TUNER_ABSENT, "TCL MPE05_2H_E"}, | ||
238 | { TUNER_ABSENT, "TCL MQNM05_4_U"}, | ||
239 | { TUNER_ABSENT, "TCL M2523_5NH_E"}, | ||
240 | /* 130-139 */ | ||
241 | { TUNER_ABSENT, "TCL M2523_3DBH_E"}, | ||
242 | { TUNER_ABSENT, "TCL M2523_3DIH_E"}, | ||
243 | { TUNER_ABSENT, "TCL MFPE05_2_U"}, | ||
244 | { TUNER_ABSENT, "Philips FMD1216MEX"}, | ||
245 | { TUNER_ABSENT, "Philips FRH2036B"}, | ||
246 | { TUNER_ABSENT, "Panasonic ENGF75_01GF"}, | ||
247 | { TUNER_ABSENT, "MaxLinear MXL5005"}, | ||
248 | { TUNER_ABSENT, "MaxLinear MXL5003"}, | ||
249 | { TUNER_ABSENT, "Xceive XC2028"}, | ||
250 | { TUNER_ABSENT, "Microtune MT2131"}, | ||
251 | /* 140-149 */ | ||
252 | { TUNER_ABSENT, "Philips 8275A_8295"}, | ||
253 | { TUNER_ABSENT, "TCL MF02GIP_5N_E"}, | ||
254 | { TUNER_ABSENT, "TCL MF02GIP_3DB_E"}, | ||
255 | { TUNER_ABSENT, "TCL MF02GIP_3DI_E"}, | ||
256 | { TUNER_ABSENT, "Microtune MT2266"}, | ||
257 | { TUNER_ABSENT, "TCL MF10WPP_4N_E"}, | ||
258 | { TUNER_ABSENT, "LG TAPQ_H702F"}, | ||
259 | { TUNER_ABSENT, "TCL M09WPP_4N_E"}, | ||
260 | { TUNER_ABSENT, "MaxLinear MXL5005_v2"}, | ||
261 | { TUNER_ABSENT, "Philips 18271_8295"}, | ||
232 | }; | 262 | }; |
233 | 263 | ||
234 | static struct HAUPPAUGE_AUDIOIC | 264 | static struct HAUPPAUGE_AUDIOIC |
@@ -280,11 +310,16 @@ audioIC[] = | |||
280 | {AUDIO_CHIP_INTERNAL, "CX883"}, | 310 | {AUDIO_CHIP_INTERNAL, "CX883"}, |
281 | {AUDIO_CHIP_INTERNAL, "CX882"}, | 311 | {AUDIO_CHIP_INTERNAL, "CX882"}, |
282 | {AUDIO_CHIP_INTERNAL, "CX25840"}, | 312 | {AUDIO_CHIP_INTERNAL, "CX25840"}, |
283 | /* 35-38 */ | 313 | /* 35-39 */ |
284 | {AUDIO_CHIP_INTERNAL, "CX25841"}, | 314 | {AUDIO_CHIP_INTERNAL, "CX25841"}, |
285 | {AUDIO_CHIP_INTERNAL, "CX25842"}, | 315 | {AUDIO_CHIP_INTERNAL, "CX25842"}, |
286 | {AUDIO_CHIP_INTERNAL, "CX25843"}, | 316 | {AUDIO_CHIP_INTERNAL, "CX25843"}, |
287 | {AUDIO_CHIP_INTERNAL, "CX23418"}, | 317 | {AUDIO_CHIP_INTERNAL, "CX23418"}, |
318 | {AUDIO_CHIP_INTERNAL, "CX23885"}, | ||
319 | /* 40-42 */ | ||
320 | {AUDIO_CHIP_INTERNAL, "CX23888"}, | ||
321 | {AUDIO_CHIP_INTERNAL, "SAA7131"}, | ||
322 | {AUDIO_CHIP_INTERNAL, "CX23887"}, | ||
288 | }; | 323 | }; |
289 | 324 | ||
290 | /* This list is supplied by Hauppauge. Thanks! */ | 325 | /* This list is supplied by Hauppauge. Thanks! */ |
@@ -301,8 +336,10 @@ static const char *decoderIC[] = { | |||
301 | "CX880", "CX881", "CX883", "SAA7111", "SAA7113", | 336 | "CX880", "CX881", "CX883", "SAA7111", "SAA7113", |
302 | /* 25-29 */ | 337 | /* 25-29 */ |
303 | "CX882", "TVP5150A", "CX25840", "CX25841", "CX25842", | 338 | "CX882", "TVP5150A", "CX25840", "CX25841", "CX25842", |
304 | /* 30-31 */ | 339 | /* 30-34 */ |
305 | "CX25843", "CX23418", | 340 | "CX25843", "CX23418", "NEC61153", "CX23885", "CX23888", |
341 | /* 35-37 */ | ||
342 | "SAA7131", "CX25837", "CX23887" | ||
306 | }; | 343 | }; |
307 | 344 | ||
308 | static int hasRadioTuner(int tunerType) | 345 | static int hasRadioTuner(int tunerType) |
diff --git a/drivers/media/video/upd64031a.c b/drivers/media/video/upd64031a.c index 28d1133a3b7a..0b2a961efd22 100644 --- a/drivers/media/video/upd64031a.c +++ b/drivers/media/video/upd64031a.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/i2c.h> | 27 | #include <linux/i2c.h> |
28 | #include <linux/videodev2.h> | 28 | #include <linux/videodev2.h> |
29 | #include <media/v4l2-common.h> | 29 | #include <media/v4l2-common.h> |
30 | #include <media/v4l2-chip-ident.h> | ||
30 | #include <media/upd64031a.h> | 31 | #include <media/upd64031a.h> |
31 | 32 | ||
32 | // --------------------- read registers functions define ----------------------- | 33 | // --------------------- read registers functions define ----------------------- |
@@ -179,6 +180,9 @@ static int upd64031a_command(struct i2c_client *client, unsigned int cmd, void * | |||
179 | } | 180 | } |
180 | #endif | 181 | #endif |
181 | 182 | ||
183 | case VIDIOC_G_CHIP_IDENT: | ||
184 | return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_UPD64031A, 0); | ||
185 | |||
182 | default: | 186 | default: |
183 | break; | 187 | break; |
184 | } | 188 | } |
diff --git a/drivers/media/video/upd64083.c b/drivers/media/video/upd64083.c index fe38224150d8..401bd21f46eb 100644 --- a/drivers/media/video/upd64083.c +++ b/drivers/media/video/upd64083.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/i2c.h> | 26 | #include <linux/i2c.h> |
27 | #include <linux/videodev2.h> | 27 | #include <linux/videodev2.h> |
28 | #include <media/v4l2-common.h> | 28 | #include <media/v4l2-common.h> |
29 | #include <media/v4l2-chip-ident.h> | ||
29 | #include <media/upd64083.h> | 30 | #include <media/upd64083.h> |
30 | 31 | ||
31 | MODULE_DESCRIPTION("uPD64083 driver"); | 32 | MODULE_DESCRIPTION("uPD64083 driver"); |
@@ -155,6 +156,10 @@ static int upd64083_command(struct i2c_client *client, unsigned int cmd, void *a | |||
155 | break; | 156 | break; |
156 | } | 157 | } |
157 | #endif | 158 | #endif |
159 | |||
160 | case VIDIOC_G_CHIP_IDENT: | ||
161 | return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_UPD64083, 0); | ||
162 | |||
158 | default: | 163 | default: |
159 | break; | 164 | break; |
160 | } | 165 | } |
diff --git a/drivers/media/video/usbvideo/usbvideo.c b/drivers/media/video/usbvideo/usbvideo.c index d34d8c8b7376..687f026753b2 100644 --- a/drivers/media/video/usbvideo/usbvideo.c +++ b/drivers/media/video/usbvideo/usbvideo.c | |||
@@ -628,24 +628,21 @@ EXPORT_SYMBOL(usbvideo_HexDump); | |||
628 | /* ******************************************************************** */ | 628 | /* ******************************************************************** */ |
629 | 629 | ||
630 | /* XXX: this piece of crap really wants some error handling.. */ | 630 | /* XXX: this piece of crap really wants some error handling.. */ |
631 | static void usbvideo_ClientIncModCount(struct uvd *uvd) | 631 | static int usbvideo_ClientIncModCount(struct uvd *uvd) |
632 | { | 632 | { |
633 | if (uvd == NULL) { | 633 | if (uvd == NULL) { |
634 | err("%s: uvd == NULL", __FUNCTION__); | 634 | err("%s: uvd == NULL", __FUNCTION__); |
635 | return; | 635 | return -EINVAL; |
636 | } | 636 | } |
637 | if (uvd->handle == NULL) { | 637 | if (uvd->handle == NULL) { |
638 | err("%s: uvd->handle == NULL", __FUNCTION__); | 638 | err("%s: uvd->handle == NULL", __FUNCTION__); |
639 | return; | 639 | return -EINVAL; |
640 | } | ||
641 | if (uvd->handle->md_module == NULL) { | ||
642 | err("%s: uvd->handle->md_module == NULL", __FUNCTION__); | ||
643 | return; | ||
644 | } | 640 | } |
645 | if (!try_module_get(uvd->handle->md_module)) { | 641 | if (!try_module_get(uvd->handle->md_module)) { |
646 | err("%s: try_module_get() == 0", __FUNCTION__); | 642 | err("%s: try_module_get() == 0", __FUNCTION__); |
647 | return; | 643 | return -ENODEV; |
648 | } | 644 | } |
645 | return 0; | ||
649 | } | 646 | } |
650 | 647 | ||
651 | static void usbvideo_ClientDecModCount(struct uvd *uvd) | 648 | static void usbvideo_ClientDecModCount(struct uvd *uvd) |
@@ -712,8 +709,6 @@ int usbvideo_register( | |||
712 | cams->num_cameras = num_cams; | 709 | cams->num_cameras = num_cams; |
713 | cams->cam = (struct uvd *) &cams[1]; | 710 | cams->cam = (struct uvd *) &cams[1]; |
714 | cams->md_module = md; | 711 | cams->md_module = md; |
715 | if (cams->md_module == NULL) | ||
716 | warn("%s: module == NULL!", __FUNCTION__); | ||
717 | mutex_init(&cams->lock); /* to 1 == available */ | 712 | mutex_init(&cams->lock); /* to 1 == available */ |
718 | 713 | ||
719 | for (i = 0; i < num_cams; i++) { | 714 | for (i = 0; i < num_cams; i++) { |
@@ -1119,7 +1114,8 @@ static int usbvideo_v4l_open(struct inode *inode, struct file *file) | |||
1119 | if (uvd->debug > 1) | 1114 | if (uvd->debug > 1) |
1120 | info("%s($%p)", __FUNCTION__, dev); | 1115 | info("%s($%p)", __FUNCTION__, dev); |
1121 | 1116 | ||
1122 | usbvideo_ClientIncModCount(uvd); | 1117 | if (0 < usbvideo_ClientIncModCount(uvd)) |
1118 | return -ENODEV; | ||
1123 | mutex_lock(&uvd->lock); | 1119 | mutex_lock(&uvd->lock); |
1124 | 1120 | ||
1125 | if (uvd->user) { | 1121 | if (uvd->user) { |
diff --git a/drivers/media/video/usbvision/usbvision-cards.c b/drivers/media/video/usbvision/usbvision-cards.c index a40e5838515b..13f69fe6360d 100644 --- a/drivers/media/video/usbvision/usbvision-cards.c +++ b/drivers/media/video/usbvision/usbvision-cards.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * USBVISION.H | 2 | * usbvision-cards.c |
3 | * usbvision header file | 3 | * usbvision cards definition file |
4 | * | 4 | * |
5 | * Copyright (c) 1999-2005 Joerg Heckenbach <joerg@heckenbach-aw.de> | 5 | * Copyright (c) 1999-2005 Joerg Heckenbach <joerg@heckenbach-aw.de> |
6 | * | 6 | * |
@@ -28,129 +28,1060 @@ | |||
28 | #include <media/v4l2-dev.h> | 28 | #include <media/v4l2-dev.h> |
29 | #include <media/tuner.h> | 29 | #include <media/tuner.h> |
30 | #include "usbvision.h" | 30 | #include "usbvision.h" |
31 | #include "usbvision-cards.h" | ||
31 | 32 | ||
32 | /* Supported Devices: A table for usbvision.c*/ | 33 | /* Supported Devices: A table for usbvision.c*/ |
33 | struct usbvision_device_data_st usbvision_device_data[] = { | 34 | struct usbvision_device_data_st usbvision_device_data[] = { |
34 | {0xFFF0, 0xFFF0, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, -1, -1, "Custom Dummy USBVision Device"}, | 35 | [XANBOO] = { |
35 | {0x0A6F, 0x0400, -1, CODEC_SAA7113, 4, V4L2_STD_NTSC, 1, 0, 1, 0, 0, -1, -1, -1, -1, -1, "Xanboo"}, | 36 | .Interface = -1, |
36 | {0x050D, 0x0208, -1, CODEC_SAA7113, 2, V4L2_STD_PAL, 1, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Belkin USBView II"}, | 37 | .Codec = CODEC_SAA7113, |
37 | {0x0571, 0x0002, 0, CODEC_SAA7111, 2, V4L2_STD_PAL, 0, 0, 1, 0, 0, -1, -1, -1, -1, 7, "echoFX InterView Lite"}, | 38 | .VideoChannels = 4, |
38 | {0x0573, 0x0003, -1, CODEC_SAA7111, 2, V4L2_STD_NTSC, 1, 0, 1, 0, 0, -1, -1, -1, -1, -1, "USBGear USBG-V1 resp. HAMA USB"}, | 39 | .VideoNorm = V4L2_STD_NTSC, |
39 | {0x0573, 0x0400, -1, CODEC_SAA7113, 4, V4L2_STD_NTSC, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "D-Link V100"}, | 40 | .AudioChannels = 1, |
40 | {0x0573, 0x2000, -1, CODEC_SAA7111, 2, V4L2_STD_NTSC, 1, 0, 1, 0, 0, -1, -1, -1, -1, -1, "X10 USB Camera"}, | 41 | .Radio = 0, |
41 | {0x0573, 0x2d00, -1, CODEC_SAA7111, 2, V4L2_STD_PAL, 1, 0, 1, 0, 0, -1, -1, -1, 3, 7, "Osprey 50"}, | 42 | .vbi = 1, |
42 | {0x0573, 0x2d01, -1, CODEC_SAA7113, 2, V4L2_STD_NTSC, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Hauppauge USB-Live Model 600"}, | 43 | .Tuner = 0, |
43 | {0x0573, 0x2101, -1, CODEC_SAA7113, 2, V4L2_STD_PAL, 2, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Zoran Co. PMD (Nogatech) AV-grabber Manhattan"}, | 44 | .TunerType = 0, |
44 | {0x0573, 0x4100, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, 20, -1, "Nogatech USB-TV (NTSC) FM"}, | 45 | .X_Offset = -1, |
45 | {0x0573, 0x4110, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, 20, -1, "PNY USB-TV (NTSC) FM"}, | 46 | .Y_Offset = -1, |
46 | {0x0573, 0x4450, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "PixelView PlayTv-USB PRO (PAL) FM"}, | 47 | .ModelString = "Xanboo", |
47 | {0x0573, 0x4550, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "ZTV ZT-721 2.4GHz USB A/V Receiver"}, | 48 | }, |
48 | {0x0573, 0x4d00, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 0, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, 20, -1, "Hauppauge WinTv-USB USA"}, | 49 | [BELKIN_VIDEOBUS_II] = { |
49 | {0x0573, 0x4d01, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 0, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, -1, -1, "Hauppauge WinTv-USB"}, | 50 | .Interface = -1, |
50 | {0x0573, 0x4d02, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 0, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, -1, -1, "Hauppauge WinTv-USB (NTSC)"}, | 51 | .Codec = CODEC_SAA7113, |
51 | {0x0573, 0x4d03, -1, CODEC_SAA7111, 3, V4L2_STD_SECAM, 1, 0, 1, 1, TUNER_PHILIPS_SECAM, -1, -1, -1, -1, -1, "Hauppauge WinTv-USB (SECAM) "}, | 52 | .VideoChannels = 2, |
52 | {0x0573, 0x4d10, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, -1, -1, "Hauppauge WinTv-USB (NTSC) FM"}, | 53 | .VideoNorm = V4L2_STD_PAL, |
53 | {0x0573, 0x4d11, -1, CODEC_SAA7111, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, -1, -1, -1, "Hauppauge WinTv-USB (PAL) FM"}, | 54 | .AudioChannels = 1, |
54 | {0x0573, 0x4d12, -1, CODEC_SAA7111, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, -1, -1, -1, "Hauppauge WinTv-USB (PAL) FM"}, | 55 | .Radio = 0, |
55 | {0x0573, 0x4d2a, 0, CODEC_SAA7113, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_MICROTUNE_4049FM5, -1, -1, 0, 3, 7, "Hauppauge WinTv USB (NTSC) FM Model 602 40201 Rev B285"}, | 56 | .vbi = 1, |
56 | {0x0573, 0x4d2b, 0, CODEC_SAA7113, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_MICROTUNE_4049FM5, -1, -1, 0, 3, 7, "Hauppauge WinTv USB (NTSC) FM Model 602 40201 Rev B282"}, | 57 | .Tuner = 0, |
57 | {0x0573, 0x4d2c, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_PHILIPS_FM1216ME_MK3, -1, -1, 0, 3, 7, "Hauppauge WinTv USB (PAL/SECAM) 40209 Rev E1A5"}, | 58 | .TunerType = 0, |
58 | {0x0573, 0x4d20, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB II (PAL) FM Model 40201 Rev B226"}, | 59 | .X_Offset = 0, |
59 | {0x0573, 0x4d21, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB II (PAL)"}, | 60 | .Y_Offset = 3, |
60 | {0x0573, 0x4d22, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB II (PAL) MODEL 566"}, | 61 | .Dvi_yuv_override = 1, |
61 | {0x0573, 0x4d23, -1, CODEC_SAA7113, 3, V4L2_STD_SECAM, 1, 0, 1, 1, TUNER_PHILIPS_SECAM, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB (SECAM) 4D23"}, | 62 | .Dvi_yuv = 7, |
62 | {0x0573, 0x4d25, -1, CODEC_SAA7113, 3, V4L2_STD_SECAM, 1, 0, 1, 1, TUNER_PHILIPS_SECAM, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB (SECAM) Model 40209 Rev B234"}, | 63 | .ModelString = "Belkin USB VideoBus II Adapter", |
63 | {0x0573, 0x4d26, -1, CODEC_SAA7113, 3, V4L2_STD_SECAM, 1, 0, 1, 1, TUNER_PHILIPS_SECAM, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB (SECAM) Model 40209 Rev B243"}, | 64 | }, |
64 | {0x0573, 0x4d27, -1, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_ALPS_TSBE1_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB Model 40204 Rev B281"}, | 65 | [BELKIN_VIDEOBUS] = { |
65 | {0x0573, 0x4d28, -1, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_ALPS_TSBE1_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB Model 40204 Rev B283"}, | 66 | .Interface = -1, |
66 | {0x0573, 0x4d29, -1, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB Model 40205 Rev B298"}, | 67 | .Codec = CODEC_SAA7111, |
67 | {0x0573, 0x4d30, -1, CODEC_SAA7113, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB FM Model 40211 Rev B123"}, | 68 | .VideoChannels = 2, |
68 | {0x0573, 0x4d31, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB III (PAL) FM Model 568"}, | 69 | .VideoNorm = V4L2_STD_NTSC, |
69 | {0x0573, 0x4d32, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB III (PAL) FM Model 573"}, | 70 | .AudioChannels = 1, |
70 | {0x0573, 0x4d35, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_MICROTUNE_4049FM5, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB III (PAL) FM Model 40219 Rev B252"}, | 71 | .Radio = 0, |
71 | {0x0573, 0x4d37, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_FM1216ME_MK3, -1, -1, 0, 3, 7, "Hauppauge WinTV USB device Model 40219 Rev E189"}, | 72 | .vbi = 1, |
72 | {0x0768, 0x0006, -1, CODEC_SAA7113, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, 5, 5, -1, "Camtel Technology USB TV Genie Pro FM Model TVB330"}, | 73 | .Tuner = 0, |
73 | {0x07d0, 0x0001, -1, CODEC_SAA7113, 2, V4L2_STD_PAL, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Digital Video Creator I"}, | 74 | .TunerType = 0, |
74 | {0x07d0, 0x0002, -1, CODEC_SAA7111, 2, V4L2_STD_NTSC, 0, 0, 1, 0, 0, -1, -1, 82, 20, 7, "Global Village GV-007 (NTSC)"}, | 75 | .X_Offset = -1, |
75 | {0x07d0, 0x0003, 0, CODEC_SAA7113, 2, V4L2_STD_NTSC, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Dazzle Fusion Model DVC-50 Rev 1 (NTSC)"}, | 76 | .Y_Offset = -1, |
76 | {0x07d0, 0x0004, 0, CODEC_SAA7113, 2, V4L2_STD_PAL, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Dazzle Fusion Model DVC-80 Rev 1 (PAL)"}, | 77 | .ModelString = "Belkin Components USB VideoBus", |
77 | {0x07d0, 0x0005, 0, CODEC_SAA7113, 2, V4L2_STD_SECAM, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Dazzle Fusion Model DVC-90 Rev 1 (SECAM)"}, | 78 | }, |
78 | {0x2304, 0x010d, -1, CODEC_SAA7111, 3, V4L2_STD_PAL, 1, 0, 0, 1, TUNER_TEMIC_4066FY5_PAL_I, -1, -1, -1, -1, -1, "Pinnacle Studio PCTV USB (PAL)"}, | 79 | [BELKIN_USB_VIDEOBUS_II] = { |
79 | {0x2304, 0x0109, -1, CODEC_SAA7111, 3, V4L2_STD_SECAM, 1, 0, 1, 1, TUNER_PHILIPS_SECAM, -1, -1, -1, -1, -1, "Pinnacle Studio PCTV USB (SECAM)"}, | 80 | .Interface = -1, |
80 | {0x2304, 0x0110, -1, CODEC_SAA7111, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1,128, 23, -1, "Pinnacle Studio PCTV USB (PAL) FM"}, | 81 | .Codec = CODEC_SAA7113, |
81 | {0x2304, 0x0111, -1, CODEC_SAA7111, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_PHILIPS_PAL, -1, -1, -1, -1, -1, "Miro PCTV USB"}, | 82 | .VideoChannels = 2, |
82 | {0x2304, 0x0112, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, -1, -1, "Pinnacle Studio PCTV USB (NTSC) FM"}, | 83 | .VideoNorm = V4L2_STD_PAL, |
83 | {0x2304, 0x0210, -1, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_TEMIC_4009FR5_PAL, -1, -1, 0, 3, 7, "Pinnacle Studio PCTV USB (PAL) FM"}, | 84 | .AudioChannels = 1, |
84 | {0x2304, 0x0212, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_TEMIC_4039FR5_NTSC, -1, -1, 0, 3, 7, "Pinnacle Studio PCTV USB (NTSC) FM"}, | 85 | .Radio = 0, |
85 | {0x2304, 0x0214, -1, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_TEMIC_4009FR5_PAL, -1, -1, 0, 3, 7, "Pinnacle Studio PCTV USB (PAL) FM"}, | 86 | .vbi = 1, |
86 | {0x2304, 0x0300, -1, CODEC_SAA7113, 2, V4L2_STD_NTSC, 1, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Pinnacle Studio Linx Video input cable (NTSC)"}, | 87 | .Tuner = 0, |
87 | {0x2304, 0x0301, -1, CODEC_SAA7113, 2, V4L2_STD_PAL, 1, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Pinnacle Studio Linx Video input cable (PAL)"}, | 88 | .TunerType = 0, |
88 | {0x2304, 0x0419, -1, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_TEMIC_4009FR5_PAL, -1, -1, 0, 3, 7, "Pinnacle PCTV Bungee USB (PAL) FM"}, | 89 | .X_Offset = 0, |
89 | {0x2400, 0x4200, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 0, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, -1, -1, "Hauppauge WinTv-USB"}, | 90 | .Y_Offset = 3, |
90 | {} /* Terminating entry */ | 91 | .Dvi_yuv_override = 1, |
92 | .Dvi_yuv = 7, | ||
93 | .ModelString = "Belkin USB VideoBus II", | ||
94 | }, | ||
95 | [ECHOFX_INTERVIEW_LITE] = { | ||
96 | .Interface = 0, | ||
97 | .Codec = CODEC_SAA7111, | ||
98 | .VideoChannels = 2, | ||
99 | .VideoNorm = V4L2_STD_PAL, | ||
100 | .AudioChannels = 0, | ||
101 | .Radio = 0, | ||
102 | .vbi = 1, | ||
103 | .Tuner = 0, | ||
104 | .TunerType = 0, | ||
105 | .X_Offset = -1, | ||
106 | .Y_Offset = -1, | ||
107 | .Dvi_yuv_override = 1, | ||
108 | .Dvi_yuv = 7, | ||
109 | .ModelString = "echoFX InterView Lite", | ||
110 | }, | ||
111 | [USBGEAR_USBG_V1] = { | ||
112 | .Interface = -1, | ||
113 | .Codec = CODEC_SAA7111, | ||
114 | .VideoChannels = 2, | ||
115 | .VideoNorm = V4L2_STD_NTSC, | ||
116 | .AudioChannels = 1, | ||
117 | .Radio = 0, | ||
118 | .vbi = 1, | ||
119 | .Tuner = 0, | ||
120 | .TunerType = 0, | ||
121 | .X_Offset = -1, | ||
122 | .Y_Offset = -1, | ||
123 | .ModelString = "USBGear USBG-V1 resp. HAMA USB", | ||
124 | }, | ||
125 | [D_LINK_V100] = { | ||
126 | .Interface = -1, | ||
127 | .Codec = CODEC_SAA7113, | ||
128 | .VideoChannels = 4, | ||
129 | .VideoNorm = V4L2_STD_NTSC, | ||
130 | .AudioChannels = 0, | ||
131 | .Radio = 0, | ||
132 | .vbi = 1, | ||
133 | .Tuner = 0, | ||
134 | .TunerType = 0, | ||
135 | .X_Offset = 0, | ||
136 | .Y_Offset = 3, | ||
137 | .Dvi_yuv_override = 1, | ||
138 | .Dvi_yuv = 7, | ||
139 | .ModelString = "D-Link V100", | ||
140 | }, | ||
141 | [X10_USB_CAMERA] = { | ||
142 | .Interface = -1, | ||
143 | .Codec = CODEC_SAA7111, | ||
144 | .VideoChannels = 2, | ||
145 | .VideoNorm = V4L2_STD_NTSC, | ||
146 | .AudioChannels = 1, | ||
147 | .Radio = 0, | ||
148 | .vbi = 1, | ||
149 | .Tuner = 0, | ||
150 | .TunerType = 0, | ||
151 | .X_Offset = -1, | ||
152 | .Y_Offset = -1, | ||
153 | .ModelString = "X10 USB Camera", | ||
154 | }, | ||
155 | [HPG_WINTV_LIVE_PAL_BG] = { | ||
156 | .Interface = -1, | ||
157 | .Codec = CODEC_SAA7111, | ||
158 | .VideoChannels = 2, | ||
159 | .VideoNorm = V4L2_STD_PAL, | ||
160 | .AudioChannels = 1, | ||
161 | .Radio = 0, | ||
162 | .vbi = 1, | ||
163 | .Tuner = 0, | ||
164 | .TunerType = 0, | ||
165 | .X_Offset = -1, | ||
166 | .Y_Offset = 3, | ||
167 | .Dvi_yuv_override = 1, | ||
168 | .Dvi_yuv = 7, | ||
169 | .ModelString = "Hauppauge WinTV USB Live (PAL B/G)", | ||
170 | }, | ||
171 | [HPG_WINTV_LIVE_PRO_NTSC_MN] = { | ||
172 | .Interface = -1, | ||
173 | .Codec = CODEC_SAA7113, | ||
174 | .VideoChannels = 2, | ||
175 | .VideoNorm = V4L2_STD_NTSC, | ||
176 | .AudioChannels = 0, | ||
177 | .Radio = 0, | ||
178 | .vbi = 1, | ||
179 | .Tuner = 0, | ||
180 | .TunerType = 0, | ||
181 | .X_Offset = 0, | ||
182 | .Y_Offset = 3, | ||
183 | .Dvi_yuv_override = 1, | ||
184 | .Dvi_yuv = 7, | ||
185 | .ModelString = "Hauppauge WinTV USB Live Pro (NTSC M/N)", | ||
186 | }, | ||
187 | [ZORAN_PMD_NOGATECH] = { | ||
188 | .Interface = -1, | ||
189 | .Codec = CODEC_SAA7113, | ||
190 | .VideoChannels = 2, | ||
191 | .VideoNorm = V4L2_STD_PAL, | ||
192 | .AudioChannels = 2, | ||
193 | .Radio = 0, | ||
194 | .vbi = 1, | ||
195 | .Tuner = 0, | ||
196 | .TunerType = 0, | ||
197 | .X_Offset = 0, | ||
198 | .Y_Offset = 3, | ||
199 | .Dvi_yuv_override = 1, | ||
200 | .Dvi_yuv = 7, | ||
201 | .ModelString = "Zoran Co. PMD (Nogatech) AV-grabber Manhattan", | ||
202 | }, | ||
203 | [NOGATECH_USB_TV_NTSC_FM] = { | ||
204 | .Interface = -1, | ||
205 | .Codec = CODEC_SAA7111, | ||
206 | .VideoChannels = 3, | ||
207 | .VideoNorm = V4L2_STD_NTSC, | ||
208 | .AudioChannels = 1, | ||
209 | .Radio = 1, | ||
210 | .vbi = 1, | ||
211 | .Tuner = 1, | ||
212 | .TunerType = TUNER_PHILIPS_NTSC_M, | ||
213 | .X_Offset = -1, | ||
214 | .Y_Offset = 20, | ||
215 | .ModelString = "Nogatech USB-TV (NTSC) FM", | ||
216 | }, | ||
217 | [PNY_USB_TV_NTSC_FM] = { | ||
218 | .Interface = -1, | ||
219 | .Codec = CODEC_SAA7111, | ||
220 | .VideoChannels = 3, | ||
221 | .VideoNorm = V4L2_STD_NTSC, | ||
222 | .AudioChannels = 1, | ||
223 | .Radio = 1, | ||
224 | .vbi = 1, | ||
225 | .Tuner = 1, | ||
226 | .TunerType = TUNER_PHILIPS_NTSC_M, | ||
227 | .X_Offset = -1, | ||
228 | .Y_Offset = 20, | ||
229 | .ModelString = "PNY USB-TV (NTSC) FM", | ||
230 | }, | ||
231 | [PV_PLAYTV_USB_PRO_PAL_FM] = { | ||
232 | .Interface = 0, | ||
233 | .Codec = CODEC_SAA7113, | ||
234 | .VideoChannels = 3, | ||
235 | .VideoNorm = V4L2_STD_PAL, | ||
236 | .AudioChannels = 1, | ||
237 | .Radio = 1, | ||
238 | .vbi = 1, | ||
239 | .Tuner = 1, | ||
240 | .TunerType = TUNER_PHILIPS_PAL, | ||
241 | .X_Offset = 0, | ||
242 | .Y_Offset = 3, | ||
243 | .Dvi_yuv_override = 1, | ||
244 | .Dvi_yuv = 7, | ||
245 | .ModelString = "PixelView PlayTv-USB PRO (PAL) FM", | ||
246 | }, | ||
247 | [ZT_721] = { | ||
248 | .Interface = 0, | ||
249 | .Codec = CODEC_SAA7113, | ||
250 | .VideoChannels = 3, | ||
251 | .VideoNorm = V4L2_STD_PAL, | ||
252 | .AudioChannels = 1, | ||
253 | .Radio = 1, | ||
254 | .vbi = 1, | ||
255 | .Tuner = 1, | ||
256 | .TunerType = TUNER_PHILIPS_PAL, | ||
257 | .X_Offset = 0, | ||
258 | .Y_Offset = 3, | ||
259 | .Dvi_yuv_override = 1, | ||
260 | .Dvi_yuv = 7, | ||
261 | .ModelString = "ZTV ZT-721 2.4GHz USB A/V Receiver", | ||
262 | }, | ||
263 | [HPG_WINTV_NTSC_MN] = { | ||
264 | .Interface = -1, | ||
265 | .Codec = CODEC_SAA7111, | ||
266 | .VideoChannels = 3, | ||
267 | .VideoNorm = V4L2_STD_NTSC, | ||
268 | .AudioChannels = 1, | ||
269 | .Radio = 0, | ||
270 | .vbi = 1, | ||
271 | .Tuner = 1, | ||
272 | .TunerType = TUNER_PHILIPS_NTSC_M, | ||
273 | .X_Offset = -1, | ||
274 | .Y_Offset = 20, | ||
275 | .ModelString = "Hauppauge WinTV USB (NTSC M/N)", | ||
276 | }, | ||
277 | [HPG_WINTV_PAL_BG] = { | ||
278 | .Interface = -1, | ||
279 | .Codec = CODEC_SAA7111, | ||
280 | .VideoChannels = 3, | ||
281 | .VideoNorm = V4L2_STD_PAL, | ||
282 | .AudioChannels = 1, | ||
283 | .Radio = 0, | ||
284 | .vbi = 1, | ||
285 | .Tuner = 1, | ||
286 | .TunerType = TUNER_PHILIPS_PAL, | ||
287 | .X_Offset = -1, | ||
288 | .Y_Offset = -1, | ||
289 | .ModelString = "Hauppauge WinTV USB (PAL B/G)", | ||
290 | }, | ||
291 | [HPG_WINTV_PAL_I] = { | ||
292 | .Interface = -1, | ||
293 | .Codec = CODEC_SAA7111, | ||
294 | .VideoChannels = 3, | ||
295 | .VideoNorm = V4L2_STD_PAL, | ||
296 | .AudioChannels = 1, | ||
297 | .Radio = 0, | ||
298 | .vbi = 1, | ||
299 | .Tuner = 1, | ||
300 | .TunerType = TUNER_PHILIPS_PAL, | ||
301 | .X_Offset = -1, | ||
302 | .Y_Offset = -1, | ||
303 | .ModelString = "Hauppauge WinTV USB (PAL I)", | ||
304 | }, | ||
305 | [HPG_WINTV_PAL_SECAM_L] = { | ||
306 | .Interface = -1, | ||
307 | .Codec = CODEC_SAA7111, | ||
308 | .VideoChannels = 3, | ||
309 | .VideoNorm = V4L2_STD_SECAM, | ||
310 | .AudioChannels = 1, | ||
311 | .Radio = 0, | ||
312 | .vbi = 1, | ||
313 | .Tuner = 1, | ||
314 | .TunerType = TUNER_PHILIPS_SECAM, | ||
315 | .X_Offset = -1, | ||
316 | .Y_Offset = -1, | ||
317 | .ModelString = "Hauppauge WinTV USB (PAL/SECAM L)", | ||
318 | }, | ||
319 | [HPG_WINTV_PAL_D_K] = { | ||
320 | .Interface = -1, | ||
321 | .Codec = CODEC_SAA7111, | ||
322 | .VideoChannels = 3, | ||
323 | .VideoNorm = V4L2_STD_PAL, | ||
324 | .AudioChannels = 1, | ||
325 | .Radio = 0, | ||
326 | .vbi = 1, | ||
327 | .Tuner = 1, | ||
328 | .TunerType = TUNER_PHILIPS_PAL, | ||
329 | .X_Offset = -1, | ||
330 | .Y_Offset = -1, | ||
331 | .ModelString = "Hauppauge WinTV USB (PAL D/K)", | ||
332 | }, | ||
333 | [HPG_WINTV_NTSC_FM] = { | ||
334 | .Interface = -1, | ||
335 | .Codec = CODEC_SAA7111, | ||
336 | .VideoChannels = 3, | ||
337 | .VideoNorm = V4L2_STD_NTSC, | ||
338 | .AudioChannels = 1, | ||
339 | .Radio = 1, | ||
340 | .vbi = 1, | ||
341 | .Tuner = 1, | ||
342 | .TunerType = TUNER_PHILIPS_NTSC_M, | ||
343 | .X_Offset = -1, | ||
344 | .Y_Offset = -1, | ||
345 | .ModelString = "Hauppauge WinTV USB (NTSC FM)", | ||
346 | }, | ||
347 | [HPG_WINTV_PAL_BG_FM] = { | ||
348 | .Interface = -1, | ||
349 | .Codec = CODEC_SAA7111, | ||
350 | .VideoChannels = 3, | ||
351 | .VideoNorm = V4L2_STD_PAL, | ||
352 | .AudioChannels = 1, | ||
353 | .Radio = 1, | ||
354 | .vbi = 1, | ||
355 | .Tuner = 1, | ||
356 | .TunerType = TUNER_PHILIPS_PAL, | ||
357 | .X_Offset = -1, | ||
358 | .Y_Offset = -1, | ||
359 | .ModelString = "Hauppauge WinTV USB (PAL B/G FM)", | ||
360 | }, | ||
361 | [HPG_WINTV_PAL_I_FM] = { | ||
362 | .Interface = -1, | ||
363 | .Codec = CODEC_SAA7111, | ||
364 | .VideoChannels = 3, | ||
365 | .VideoNorm = V4L2_STD_PAL, | ||
366 | .AudioChannels = 1, | ||
367 | .Radio = 1, | ||
368 | .vbi = 1, | ||
369 | .Tuner = 1, | ||
370 | .TunerType = TUNER_PHILIPS_PAL, | ||
371 | .X_Offset = -1, | ||
372 | .Y_Offset = -1, | ||
373 | .ModelString = "Hauppauge WinTV USB (PAL I FM)", | ||
374 | }, | ||
375 | [HPG_WINTV_PAL_D_K_FM] = { | ||
376 | .Interface = -1, | ||
377 | .Codec = CODEC_SAA7111, | ||
378 | .VideoChannels = 3, | ||
379 | .VideoNorm = V4L2_STD_PAL, | ||
380 | .AudioChannels = 1, | ||
381 | .Radio = 1, | ||
382 | .vbi = 1, | ||
383 | .Tuner = 1, | ||
384 | .TunerType = TUNER_PHILIPS_PAL, | ||
385 | .X_Offset = -1, | ||
386 | .Y_Offset = -1, | ||
387 | .ModelString = "Hauppauge WinTV USB (PAL D/K FM)", | ||
388 | }, | ||
389 | [HPG_WINTV_PRO_NTSC_MN] = { | ||
390 | .Interface = 0, | ||
391 | .Codec = CODEC_SAA7113, | ||
392 | .VideoChannels = 3, | ||
393 | .VideoNorm = V4L2_STD_NTSC, | ||
394 | .AudioChannels = 1, | ||
395 | .Radio = 1, | ||
396 | .vbi = 1, | ||
397 | .Tuner = 1, | ||
398 | .TunerType = TUNER_MICROTUNE_4049FM5, | ||
399 | .X_Offset = 0, | ||
400 | .Y_Offset = 3, | ||
401 | .Dvi_yuv_override = 1, | ||
402 | .Dvi_yuv = 7, | ||
403 | .ModelString = "Hauppauge WinTV USB Pro (NTSC M/N)", | ||
404 | }, | ||
405 | [HPG_WINTV_PRO_NTSC_MN_V2] = { | ||
406 | .Interface = 0, | ||
407 | .Codec = CODEC_SAA7113, | ||
408 | .VideoChannels = 3, | ||
409 | .VideoNorm = V4L2_STD_NTSC, | ||
410 | .AudioChannels = 1, | ||
411 | .Radio = 1, | ||
412 | .vbi = 1, | ||
413 | .Tuner = 1, | ||
414 | .TunerType = TUNER_MICROTUNE_4049FM5, | ||
415 | .X_Offset = 0, | ||
416 | .Y_Offset = 3, | ||
417 | .Dvi_yuv_override = 1, | ||
418 | .Dvi_yuv = 7, | ||
419 | .ModelString = "Hauppauge WinTV USB Pro (NTSC M/N) V2", | ||
420 | }, | ||
421 | [HPG_WINTV_PRO_PAL] = { | ||
422 | .Interface = 0, | ||
423 | .Codec = CODEC_SAA7113, | ||
424 | .VideoChannels = 3, | ||
425 | .VideoNorm = V4L2_STD_PAL, | ||
426 | .AudioChannels = 1, | ||
427 | .Radio = 0, | ||
428 | .vbi = 1, | ||
429 | .Tuner = 1, | ||
430 | .TunerType = TUNER_PHILIPS_FM1216ME_MK3, | ||
431 | .X_Offset = 0, | ||
432 | .Y_Offset = 3, | ||
433 | .Dvi_yuv_override = 1, | ||
434 | .Dvi_yuv = 7, | ||
435 | .ModelString = "Hauppauge WinTV USB Pro (PAL/SECAM B/G/I/D/K/L)", | ||
436 | }, | ||
437 | [HPG_WINTV_PRO_NTSC_MN_V3] = { | ||
438 | .Interface = 0, | ||
439 | .Codec = CODEC_SAA7113, | ||
440 | .VideoChannels = 3, | ||
441 | .VideoNorm = V4L2_STD_NTSC, | ||
442 | .AudioChannels = 1, | ||
443 | .Radio = 1, | ||
444 | .vbi = 1, | ||
445 | .Tuner = 1, | ||
446 | .TunerType = TUNER_PHILIPS_NTSC_M, | ||
447 | .X_Offset = 0, | ||
448 | .Y_Offset = 3, | ||
449 | .Dvi_yuv_override = 1, | ||
450 | .Dvi_yuv = 7, | ||
451 | .ModelString = "Hauppauge WinTV USB Pro (NTSC M/N) V3", | ||
452 | }, | ||
453 | [HPG_WINTV_PRO_PAL_BG] = { | ||
454 | .Interface = 0, | ||
455 | .Codec = CODEC_SAA7113, | ||
456 | .VideoChannels = 3, | ||
457 | .VideoNorm = V4L2_STD_PAL, | ||
458 | .AudioChannels = 1, | ||
459 | .Radio = 0, | ||
460 | .vbi = 1, | ||
461 | .Tuner = 1, | ||
462 | .TunerType = TUNER_PHILIPS_PAL, | ||
463 | .X_Offset = 0, | ||
464 | .Y_Offset = 3, | ||
465 | .Dvi_yuv_override = 1, | ||
466 | .Dvi_yuv = 7, | ||
467 | .ModelString = "Hauppauge WinTV USB Pro (PAL B/G)", | ||
468 | }, | ||
469 | [HPG_WINTV_PRO_PAL_I] = { | ||
470 | .Interface = 0, | ||
471 | .Codec = CODEC_SAA7113, | ||
472 | .VideoChannels = 3, | ||
473 | .VideoNorm = V4L2_STD_PAL, | ||
474 | .AudioChannels = 1, | ||
475 | .Radio = 0, | ||
476 | .vbi = 1, | ||
477 | .Tuner = 1, | ||
478 | .TunerType = TUNER_PHILIPS_PAL, | ||
479 | .X_Offset = 0, | ||
480 | .Y_Offset = 3, | ||
481 | .Dvi_yuv_override = 1, | ||
482 | .Dvi_yuv = 7, | ||
483 | .ModelString = "Hauppauge WinTV USB Pro (PAL I)", | ||
484 | }, | ||
485 | [HPG_WINTV_PRO_PAL_SECAM_L] = { | ||
486 | .Interface = -1, | ||
487 | .Codec = CODEC_SAA7113, | ||
488 | .VideoChannels = 3, | ||
489 | .VideoNorm = V4L2_STD_SECAM, | ||
490 | .AudioChannels = 1, | ||
491 | .Radio = 0, | ||
492 | .vbi = 1, | ||
493 | .Tuner = 1, | ||
494 | .TunerType = TUNER_PHILIPS_SECAM, | ||
495 | .X_Offset = 0, | ||
496 | .Y_Offset = 3, | ||
497 | .Dvi_yuv_override = 1, | ||
498 | .Dvi_yuv = 7, | ||
499 | .ModelString = "Hauppauge WinTV USB Pro (PAL/SECAM L)", | ||
500 | }, | ||
501 | [HPG_WINTV_PRO_PAL_D_K] = { | ||
502 | .Interface = -1, | ||
503 | .Codec = CODEC_SAA7113, | ||
504 | .VideoChannels = 3, | ||
505 | .VideoNorm = V4L2_STD_PAL, | ||
506 | .AudioChannels = 1, | ||
507 | .Radio = 0, | ||
508 | .vbi = 1, | ||
509 | .Tuner = 1, | ||
510 | .TunerType = TUNER_PHILIPS_PAL, | ||
511 | .X_Offset = 0, | ||
512 | .Y_Offset = 3, | ||
513 | .Dvi_yuv_override = 1, | ||
514 | .Dvi_yuv = 7, | ||
515 | .ModelString = "Hauppauge WinTV USB Pro (PAL D/K)", | ||
516 | }, | ||
517 | [HPG_WINTV_PRO_PAL_SECAM] = { | ||
518 | .Interface = -1, | ||
519 | .Codec = CODEC_SAA7113, | ||
520 | .VideoChannels = 3, | ||
521 | .VideoNorm = V4L2_STD_SECAM, | ||
522 | .AudioChannels = 1, | ||
523 | .Radio = 0, | ||
524 | .vbi = 1, | ||
525 | .Tuner = 1, | ||
526 | .TunerType = TUNER_PHILIPS_SECAM, | ||
527 | .X_Offset = 0, | ||
528 | .Y_Offset = 3, | ||
529 | .Dvi_yuv_override = 1, | ||
530 | .Dvi_yuv = 7, | ||
531 | .ModelString = "Hauppauge WinTV USB Pro (PAL/SECAM BGDK/I/L)", | ||
532 | }, | ||
533 | [HPG_WINTV_PRO_PAL_SECAM_V2] = { | ||
534 | .Interface = -1, | ||
535 | .Codec = CODEC_SAA7113, | ||
536 | .VideoChannels = 3, | ||
537 | .VideoNorm = V4L2_STD_SECAM, | ||
538 | .AudioChannels = 1, | ||
539 | .Radio = 0, | ||
540 | .vbi = 1, | ||
541 | .Tuner = 1, | ||
542 | .TunerType = TUNER_PHILIPS_SECAM, | ||
543 | .X_Offset = 0, | ||
544 | .Y_Offset = 3, | ||
545 | .Dvi_yuv_override = 1, | ||
546 | .Dvi_yuv = 7, | ||
547 | .ModelString = "Hauppauge WinTV USB Pro (PAL/SECAM BGDK/I/L) V2", | ||
548 | }, | ||
549 | [HPG_WINTV_PRO_PAL_BG_V2] = { | ||
550 | .Interface = -1, | ||
551 | .Codec = CODEC_SAA7113, | ||
552 | .VideoChannels = 3, | ||
553 | .VideoNorm = V4L2_STD_PAL, | ||
554 | .AudioChannels = 1, | ||
555 | .Radio = 0, | ||
556 | .vbi = 1, | ||
557 | .Tuner = 1, | ||
558 | .TunerType = TUNER_ALPS_TSBE1_PAL, | ||
559 | .X_Offset = 0, | ||
560 | .Y_Offset = 3, | ||
561 | .Dvi_yuv_override = 1, | ||
562 | .Dvi_yuv = 7, | ||
563 | .ModelString = "Hauppauge WinTV USB Pro (PAL B/G) V2", | ||
564 | }, | ||
565 | [HPG_WINTV_PRO_PAL_BG_D_K] = { | ||
566 | .Interface = -1, | ||
567 | .Codec = CODEC_SAA7113, | ||
568 | .VideoChannels = 3, | ||
569 | .VideoNorm = V4L2_STD_PAL, | ||
570 | .AudioChannels = 1, | ||
571 | .Radio = 0, | ||
572 | .vbi = 1, | ||
573 | .Tuner = 1, | ||
574 | .TunerType = TUNER_ALPS_TSBE1_PAL, | ||
575 | .X_Offset = 0, | ||
576 | .Y_Offset = 3, | ||
577 | .Dvi_yuv_override = 1, | ||
578 | .Dvi_yuv = 7, | ||
579 | .ModelString = "Hauppauge WinTV USB Pro (PAL B/G,D/K)", | ||
580 | }, | ||
581 | [HPG_WINTV_PRO_PAL_I_D_K] = { | ||
582 | .Interface = -1, | ||
583 | .Codec = CODEC_SAA7113, | ||
584 | .VideoChannels = 3, | ||
585 | .VideoNorm = V4L2_STD_PAL, | ||
586 | .AudioChannels = 1, | ||
587 | .Radio = 0, | ||
588 | .vbi = 1, | ||
589 | .Tuner = 1, | ||
590 | .TunerType = TUNER_PHILIPS_PAL, | ||
591 | .X_Offset = 0, | ||
592 | .Y_Offset = 3, | ||
593 | .Dvi_yuv_override = 1, | ||
594 | .Dvi_yuv = 7, | ||
595 | .ModelString = "Hauppauge WinTV USB Pro (PAL I,D/K)", | ||
596 | }, | ||
597 | [HPG_WINTV_PRO_NTSC_MN_FM] = { | ||
598 | .Interface = -1, | ||
599 | .Codec = CODEC_SAA7113, | ||
600 | .VideoChannels = 3, | ||
601 | .VideoNorm = V4L2_STD_NTSC, | ||
602 | .AudioChannels = 1, | ||
603 | .Radio = 1, | ||
604 | .vbi = 1, | ||
605 | .Tuner = 1, | ||
606 | .TunerType = TUNER_PHILIPS_NTSC_M, | ||
607 | .X_Offset = 0, | ||
608 | .Y_Offset = 3, | ||
609 | .Dvi_yuv_override = 1, | ||
610 | .Dvi_yuv = 7, | ||
611 | .ModelString = "Hauppauge WinTV USB Pro (NTSC M/N FM)", | ||
612 | }, | ||
613 | [HPG_WINTV_PRO_PAL_BG_FM] = { | ||
614 | .Interface = 0, | ||
615 | .Codec = CODEC_SAA7113, | ||
616 | .VideoChannels = 3, | ||
617 | .VideoNorm = V4L2_STD_PAL, | ||
618 | .AudioChannels = 1, | ||
619 | .Radio = 1, | ||
620 | .vbi = 1, | ||
621 | .Tuner = 1, | ||
622 | .TunerType = TUNER_PHILIPS_PAL, | ||
623 | .X_Offset = 0, | ||
624 | .Y_Offset = 3, | ||
625 | .Dvi_yuv_override = 1, | ||
626 | .Dvi_yuv = 7, | ||
627 | .ModelString = "Hauppauge WinTV USB Pro (PAL B/G FM)", | ||
628 | }, | ||
629 | [HPG_WINTV_PRO_PAL_I_FM] = { | ||
630 | .Interface = 0, | ||
631 | .Codec = CODEC_SAA7113, | ||
632 | .VideoChannels = 3, | ||
633 | .VideoNorm = V4L2_STD_PAL, | ||
634 | .AudioChannels = 1, | ||
635 | .Radio = 1, | ||
636 | .vbi = 1, | ||
637 | .Tuner = 1, | ||
638 | .TunerType = TUNER_PHILIPS_PAL, | ||
639 | .X_Offset = 0, | ||
640 | .Y_Offset = 3, | ||
641 | .Dvi_yuv_override = 1, | ||
642 | .Dvi_yuv = 7, | ||
643 | .ModelString = "Hauppauge WinTV USB Pro (PAL I FM)", | ||
644 | }, | ||
645 | [HPG_WINTV_PRO_PAL_D_K_FM] = { | ||
646 | .Interface = 0, | ||
647 | .Codec = CODEC_SAA7113, | ||
648 | .VideoChannels = 3, | ||
649 | .VideoNorm = V4L2_STD_PAL, | ||
650 | .AudioChannels = 1, | ||
651 | .Radio = 1, | ||
652 | .vbi = 1, | ||
653 | .Tuner = 1, | ||
654 | .TunerType = TUNER_PHILIPS_PAL, | ||
655 | .X_Offset = 0, | ||
656 | .Y_Offset = 3, | ||
657 | .Dvi_yuv_override = 1, | ||
658 | .Dvi_yuv = 7, | ||
659 | .ModelString = "Hauppauge WinTV USB Pro (PAL D/K FM)", | ||
660 | }, | ||
661 | [HPG_WINTV_PRO_TEMIC_PAL_FM] = { | ||
662 | .Interface = 0, | ||
663 | .Codec = CODEC_SAA7113, | ||
664 | .VideoChannels = 3, | ||
665 | .VideoNorm = V4L2_STD_PAL, | ||
666 | .AudioChannels = 1, | ||
667 | .Radio = 1, | ||
668 | .vbi = 1, | ||
669 | .Tuner = 1, | ||
670 | .TunerType = TUNER_MICROTUNE_4049FM5, | ||
671 | .X_Offset = 0, | ||
672 | .Y_Offset = 3, | ||
673 | .Dvi_yuv_override = 1, | ||
674 | .Dvi_yuv = 7, | ||
675 | .ModelString = "Hauppauge WinTV USB Pro (Temic PAL/SECAM B/G/I/D/K/L FM)", | ||
676 | }, | ||
677 | [HPG_WINTV_PRO_TEMIC_PAL_BG_FM] = { | ||
678 | .Interface = 0, | ||
679 | .Codec = CODEC_SAA7113, | ||
680 | .VideoChannels = 3, | ||
681 | .VideoNorm = V4L2_STD_PAL, | ||
682 | .AudioChannels = 1, | ||
683 | .Radio = 1, | ||
684 | .vbi = 1, | ||
685 | .Tuner = 1, | ||
686 | .TunerType = TUNER_MICROTUNE_4049FM5, | ||
687 | .X_Offset = 0, | ||
688 | .Y_Offset = 3, | ||
689 | .Dvi_yuv_override = 1, | ||
690 | .Dvi_yuv = 7, | ||
691 | .ModelString = "Hauppauge WinTV USB Pro (Temic PAL B/G FM)", | ||
692 | }, | ||
693 | [HPG_WINTV_PRO_PAL_FM] = { | ||
694 | .Interface = 0, | ||
695 | .Codec = CODEC_SAA7113, | ||
696 | .VideoChannels = 3, | ||
697 | .VideoNorm = V4L2_STD_PAL, | ||
698 | .AudioChannels = 1, | ||
699 | .Radio = 1, | ||
700 | .vbi = 1, | ||
701 | .Tuner = 1, | ||
702 | .TunerType = TUNER_PHILIPS_FM1216ME_MK3, | ||
703 | .X_Offset = 0, | ||
704 | .Y_Offset = 3, | ||
705 | .Dvi_yuv_override = 1, | ||
706 | .Dvi_yuv = 7, | ||
707 | .ModelString = "Hauppauge WinTV USB Pro (PAL/SECAM B/G/I/D/K/L FM)", | ||
708 | }, | ||
709 | [HPG_WINTV_PRO_NTSC_MN_FM_V2] = { | ||
710 | .Interface = 0, | ||
711 | .Codec = CODEC_SAA7113, | ||
712 | .VideoChannels = 3, | ||
713 | .VideoNorm = V4L2_STD_NTSC, | ||
714 | .AudioChannels = 1, | ||
715 | .Radio = 1, | ||
716 | .vbi = 1, | ||
717 | .Tuner = 1, | ||
718 | .TunerType = TUNER_PHILIPS_NTSC_M, | ||
719 | .X_Offset = 0, | ||
720 | .Y_Offset = 3, | ||
721 | .Dvi_yuv_override = 1, | ||
722 | .Dvi_yuv = 7, | ||
723 | .ModelString = "Hauppauge WinTV USB Pro (NTSC M/N FM) V2", | ||
724 | }, | ||
725 | [CAMTEL_TVB330] = { | ||
726 | .Interface = -1, | ||
727 | .Codec = CODEC_SAA7113, | ||
728 | .VideoChannels = 3, | ||
729 | .VideoNorm = V4L2_STD_NTSC, | ||
730 | .AudioChannels = 1, | ||
731 | .Radio = 1, | ||
732 | .vbi = 1, | ||
733 | .Tuner = 1, | ||
734 | .TunerType = TUNER_PHILIPS_NTSC_M, | ||
735 | .X_Offset = 5, | ||
736 | .Y_Offset = 5, | ||
737 | .ModelString = "Camtel Technology USB TV Genie Pro FM Model TVB330", | ||
738 | }, | ||
739 | [DIGITAL_VIDEO_CREATOR_I] = { | ||
740 | .Interface = -1, | ||
741 | .Codec = CODEC_SAA7113, | ||
742 | .VideoChannels = 2, | ||
743 | .VideoNorm = V4L2_STD_PAL, | ||
744 | .AudioChannels = 0, | ||
745 | .Radio = 0, | ||
746 | .vbi = 1, | ||
747 | .Tuner = 0, | ||
748 | .TunerType = 0, | ||
749 | .X_Offset = 0, | ||
750 | .Y_Offset = 3, | ||
751 | .Dvi_yuv_override = 1, | ||
752 | .Dvi_yuv = 7, | ||
753 | .ModelString = "Digital Video Creator I", | ||
754 | }, | ||
755 | [GLOBAL_VILLAGE_GV_007_NTSC] = { | ||
756 | .Interface = -1, | ||
757 | .Codec = CODEC_SAA7111, | ||
758 | .VideoChannels = 2, | ||
759 | .VideoNorm = V4L2_STD_NTSC, | ||
760 | .AudioChannels = 0, | ||
761 | .Radio = 0, | ||
762 | .vbi = 1, | ||
763 | .Tuner = 0, | ||
764 | .TunerType = 0, | ||
765 | .X_Offset = 82, | ||
766 | .Y_Offset = 20, | ||
767 | .Dvi_yuv_override = 1, | ||
768 | .Dvi_yuv = 7, | ||
769 | .ModelString = "Global Village GV-007 (NTSC)", | ||
770 | }, | ||
771 | [DAZZLE_DVC_50_REV_1_NTSC] = { | ||
772 | .Interface = 0, | ||
773 | .Codec = CODEC_SAA7113, | ||
774 | .VideoChannels = 2, | ||
775 | .VideoNorm = V4L2_STD_NTSC, | ||
776 | .AudioChannels = 0, | ||
777 | .Radio = 0, | ||
778 | .vbi = 1, | ||
779 | .Tuner = 0, | ||
780 | .TunerType = 0, | ||
781 | .X_Offset = 0, | ||
782 | .Y_Offset = 3, | ||
783 | .Dvi_yuv_override = 1, | ||
784 | .Dvi_yuv = 7, | ||
785 | .ModelString = "Dazzle Fusion Model DVC-50 Rev 1 (NTSC)", | ||
786 | }, | ||
787 | [DAZZLE_DVC_80_REV_1_PAL] = { | ||
788 | .Interface = 0, | ||
789 | .Codec = CODEC_SAA7113, | ||
790 | .VideoChannels = 2, | ||
791 | .VideoNorm = V4L2_STD_PAL, | ||
792 | .AudioChannels = 0, | ||
793 | .Radio = 0, | ||
794 | .vbi = 1, | ||
795 | .Tuner = 0, | ||
796 | .TunerType = 0, | ||
797 | .X_Offset = 0, | ||
798 | .Y_Offset = 3, | ||
799 | .Dvi_yuv_override = 1, | ||
800 | .Dvi_yuv = 7, | ||
801 | .ModelString = "Dazzle Fusion Model DVC-80 Rev 1 (PAL)", | ||
802 | }, | ||
803 | [DAZZLE_DVC_90_REV_1_SECAM] = { | ||
804 | .Interface = 0, | ||
805 | .Codec = CODEC_SAA7113, | ||
806 | .VideoChannels = 2, | ||
807 | .VideoNorm = V4L2_STD_SECAM, | ||
808 | .AudioChannels = 0, | ||
809 | .Radio = 0, | ||
810 | .vbi = 1, | ||
811 | .Tuner = 0, | ||
812 | .TunerType = 0, | ||
813 | .X_Offset = 0, | ||
814 | .Y_Offset = 3, | ||
815 | .Dvi_yuv_override = 1, | ||
816 | .Dvi_yuv = 7, | ||
817 | .ModelString = "Dazzle Fusion Model DVC-90 Rev 1 (SECAM)", | ||
818 | }, | ||
819 | [ESKAPE_LABS_MYTV2GO] = { | ||
820 | .Interface = 0, | ||
821 | .Codec = CODEC_SAA7113, | ||
822 | .VideoChannels = 2, | ||
823 | .VideoNorm = V4L2_STD_PAL, | ||
824 | .AudioChannels = 1, | ||
825 | .Radio = 1, | ||
826 | .vbi = 1, | ||
827 | .Tuner = 1, | ||
828 | .TunerType = TUNER_PHILIPS_FM1216ME_MK3, | ||
829 | .X_Offset = 0, | ||
830 | .Y_Offset = 3, | ||
831 | .Dvi_yuv_override = 1, | ||
832 | .Dvi_yuv = 7, | ||
833 | .ModelString = "Eskape Labs MyTV2Go", | ||
834 | }, | ||
835 | [PINNA_PCTV_USB_PAL] = { | ||
836 | .Interface = -1, | ||
837 | .Codec = CODEC_SAA7111, | ||
838 | .VideoChannels = 3, | ||
839 | .VideoNorm = V4L2_STD_PAL, | ||
840 | .AudioChannels = 1, | ||
841 | .Radio = 0, | ||
842 | .vbi = 0, | ||
843 | .Tuner = 1, | ||
844 | .TunerType = TUNER_TEMIC_4066FY5_PAL_I, | ||
845 | .X_Offset = -1, | ||
846 | .Y_Offset = -1, | ||
847 | .ModelString = "Pinnacle Studio PCTV USB (PAL)", | ||
848 | }, | ||
849 | [PINNA_PCTV_USB_SECAM] = { | ||
850 | .Interface = -1, | ||
851 | .Codec = CODEC_SAA7111, | ||
852 | .VideoChannels = 3, | ||
853 | .VideoNorm = V4L2_STD_SECAM, | ||
854 | .AudioChannels = 1, | ||
855 | .Radio = 0, | ||
856 | .vbi = 1, | ||
857 | .Tuner = 1, | ||
858 | .TunerType = TUNER_PHILIPS_SECAM, | ||
859 | .X_Offset = -1, | ||
860 | .Y_Offset = -1, | ||
861 | .ModelString = "Pinnacle Studio PCTV USB (SECAM)", | ||
862 | }, | ||
863 | [PINNA_PCTV_USB_PAL_FM] = { | ||
864 | .Interface = -1, | ||
865 | .Codec = CODEC_SAA7111, | ||
866 | .VideoChannels = 3, | ||
867 | .VideoNorm = V4L2_STD_PAL, | ||
868 | .AudioChannels = 1, | ||
869 | .Radio = 1, | ||
870 | .vbi = 1, | ||
871 | .Tuner = 1, | ||
872 | .TunerType = TUNER_PHILIPS_PAL, | ||
873 | .X_Offset = 128, | ||
874 | .Y_Offset = 23, | ||
875 | .ModelString = "Pinnacle Studio PCTV USB (PAL) FM", | ||
876 | }, | ||
877 | [MIRO_PCTV_USB] = { | ||
878 | .Interface = -1, | ||
879 | .Codec = CODEC_SAA7111, | ||
880 | .VideoChannels = 3, | ||
881 | .VideoNorm = V4L2_STD_PAL, | ||
882 | .AudioChannels = 1, | ||
883 | .Radio = 0, | ||
884 | .vbi = 1, | ||
885 | .Tuner = 1, | ||
886 | .TunerType = TUNER_PHILIPS_PAL, | ||
887 | .X_Offset = -1, | ||
888 | .Y_Offset = -1, | ||
889 | .ModelString = "Miro PCTV USB", | ||
890 | }, | ||
891 | [PINNA_PCTV_USB_NTSC_FM] = { | ||
892 | .Interface = -1, | ||
893 | .Codec = CODEC_SAA7111, | ||
894 | .VideoChannels = 3, | ||
895 | .VideoNorm = V4L2_STD_NTSC, | ||
896 | .AudioChannels = 1, | ||
897 | .Radio = 1, | ||
898 | .vbi = 1, | ||
899 | .Tuner = 1, | ||
900 | .TunerType = TUNER_PHILIPS_NTSC_M, | ||
901 | .X_Offset = -1, | ||
902 | .Y_Offset = -1, | ||
903 | .ModelString = "Pinnacle Studio PCTV USB (NTSC) FM", | ||
904 | }, | ||
905 | [PINNA_PCTV_USB_PAL_FM_V2] = { | ||
906 | .Interface = -1, | ||
907 | .Codec = CODEC_SAA7113, | ||
908 | .VideoChannels = 3, | ||
909 | .VideoNorm = V4L2_STD_PAL, | ||
910 | .AudioChannels = 1, | ||
911 | .Radio = 1, | ||
912 | .vbi = 1, | ||
913 | .Tuner = 1, | ||
914 | .TunerType = TUNER_TEMIC_4009FR5_PAL, | ||
915 | .X_Offset = 0, | ||
916 | .Y_Offset = 3, | ||
917 | .Dvi_yuv_override = 1, | ||
918 | .Dvi_yuv = 7, | ||
919 | .ModelString = "Pinnacle Studio PCTV USB (PAL) FM V2", | ||
920 | }, | ||
921 | [PINNA_PCTV_USB_NTSC_FM_V2] = { | ||
922 | .Interface = -1, | ||
923 | .Codec = CODEC_SAA7111, | ||
924 | .VideoChannels = 3, | ||
925 | .VideoNorm = V4L2_STD_NTSC, | ||
926 | .AudioChannels = 1, | ||
927 | .Radio = 1, | ||
928 | .vbi = 1, | ||
929 | .Tuner = 1, | ||
930 | .TunerType = TUNER_TEMIC_4039FR5_NTSC, | ||
931 | .X_Offset = 0, | ||
932 | .Y_Offset = 3, | ||
933 | .Dvi_yuv_override = 1, | ||
934 | .Dvi_yuv = 7, | ||
935 | .ModelString = "Pinnacle Studio PCTV USB (NTSC) FM V2", | ||
936 | }, | ||
937 | [PINNA_PCTV_USB_PAL_FM_V3] = { | ||
938 | .Interface = -1, | ||
939 | .Codec = CODEC_SAA7113, | ||
940 | .VideoChannels = 3, | ||
941 | .VideoNorm = V4L2_STD_PAL, | ||
942 | .AudioChannels = 1, | ||
943 | .Radio = 1, | ||
944 | .vbi = 1, | ||
945 | .Tuner = 1, | ||
946 | .TunerType = TUNER_TEMIC_4009FR5_PAL, | ||
947 | .X_Offset = 0, | ||
948 | .Y_Offset = 3, | ||
949 | .Dvi_yuv_override = 1, | ||
950 | .Dvi_yuv = 7, | ||
951 | .ModelString = "Pinnacle Studio PCTV USB (PAL) FM V3", | ||
952 | }, | ||
953 | [PINNA_LINX_VD_IN_CAB_NTSC] = { | ||
954 | .Interface = -1, | ||
955 | .Codec = CODEC_SAA7113, | ||
956 | .VideoChannels = 2, | ||
957 | .VideoNorm = V4L2_STD_NTSC, | ||
958 | .AudioChannels = 1, | ||
959 | .Radio = 0, | ||
960 | .vbi = 1, | ||
961 | .Tuner = 0, | ||
962 | .TunerType = 0, | ||
963 | .X_Offset = 0, | ||
964 | .Y_Offset = 3, | ||
965 | .Dvi_yuv_override = 1, | ||
966 | .Dvi_yuv = 7, | ||
967 | .ModelString = "Pinnacle Studio Linx Video input cable (NTSC)", | ||
968 | }, | ||
969 | [PINNA_LINX_VD_IN_CAB_PAL] = { | ||
970 | .Interface = -1, | ||
971 | .Codec = CODEC_SAA7113, | ||
972 | .VideoChannels = 2, | ||
973 | .VideoNorm = V4L2_STD_PAL, | ||
974 | .AudioChannels = 1, | ||
975 | .Radio = 0, | ||
976 | .vbi = 1, | ||
977 | .Tuner = 0, | ||
978 | .TunerType = 0, | ||
979 | .X_Offset = 0, | ||
980 | .Y_Offset = 3, | ||
981 | .Dvi_yuv_override = 1, | ||
982 | .Dvi_yuv = 7, | ||
983 | .ModelString = "Pinnacle Studio Linx Video input cable (PAL)", | ||
984 | }, | ||
985 | [PINNA_PCTV_BUNGEE_PAL_FM] = { | ||
986 | .Interface = -1, | ||
987 | .Codec = CODEC_SAA7113, | ||
988 | .VideoChannels = 3, | ||
989 | .VideoNorm = V4L2_STD_PAL, | ||
990 | .AudioChannels = 1, | ||
991 | .Radio = 1, | ||
992 | .vbi = 1, | ||
993 | .Tuner = 1, | ||
994 | .TunerType = TUNER_TEMIC_4009FR5_PAL, | ||
995 | .X_Offset = 0, | ||
996 | .Y_Offset = 3, | ||
997 | .Dvi_yuv_override = 1, | ||
998 | .Dvi_yuv = 7, | ||
999 | .ModelString = "Pinnacle PCTV Bungee USB (PAL) FM", | ||
1000 | }, | ||
1001 | [HPG_WINTV] = { | ||
1002 | .Interface = -1, | ||
1003 | .Codec = CODEC_SAA7111, | ||
1004 | .VideoChannels = 3, | ||
1005 | .VideoNorm = V4L2_STD_NTSC, | ||
1006 | .AudioChannels = 1, | ||
1007 | .Radio = 0, | ||
1008 | .vbi = 1, | ||
1009 | .Tuner = 1, | ||
1010 | .TunerType = TUNER_PHILIPS_NTSC_M, | ||
1011 | .X_Offset = -1, | ||
1012 | .Y_Offset = -1, | ||
1013 | .ModelString = "Hauppauge WinTv-USB", | ||
1014 | }, | ||
91 | }; | 1015 | }; |
1016 | const int usbvision_device_data_size=ARRAY_SIZE(usbvision_device_data); | ||
92 | 1017 | ||
93 | /* Supported Devices */ | 1018 | /* Supported Devices */ |
94 | 1019 | ||
95 | struct usb_device_id usbvision_table [] = { | 1020 | struct usb_device_id usbvision_table [] = { |
96 | { USB_DEVICE(0xFFF0, 0xFFF0) }, /* Custom Dummy USBVision Device */ | 1021 | { USB_DEVICE(0x0a6f, 0x0400), .driver_info=XANBOO }, |
97 | { USB_DEVICE(0x0A6F, 0x0400) }, /* Xanboo */ | 1022 | { USB_DEVICE(0x050d, 0x0106), .driver_info=BELKIN_VIDEOBUS_II }, |
98 | { USB_DEVICE(0x050d, 0x0208) }, /* Belkin USBView II */ | 1023 | { USB_DEVICE(0x050d, 0x0207), .driver_info=BELKIN_VIDEOBUS }, |
99 | { USB_DEVICE(0x0571, 0x0002) }, /* echoFX InterView Lite */ | 1024 | { USB_DEVICE(0x050d, 0x0208), .driver_info=BELKIN_USB_VIDEOBUS_II }, |
100 | { USB_DEVICE(0x0573, 0x0003) }, /* USBGear USBG-V1 */ | 1025 | { USB_DEVICE(0x0571, 0x0002), .driver_info=ECHOFX_INTERVIEW_LITE }, |
101 | { USB_DEVICE(0x0573, 0x0400) }, /* D-Link V100 */ | 1026 | { USB_DEVICE(0x0573, 0x0003), .driver_info=USBGEAR_USBG_V1 }, |
102 | { USB_DEVICE(0x0573, 0x2000) }, /* X10 USB Camera */ | 1027 | { USB_DEVICE(0x0573, 0x0400), .driver_info=D_LINK_V100 }, |
103 | { USB_DEVICE(0x0573, 0x2d00) }, /* Osprey 50 */ | 1028 | { USB_DEVICE(0x0573, 0x2000), .driver_info=X10_USB_CAMERA }, |
104 | { USB_DEVICE(0x0573, 0x2d01) }, /* Hauppauge USB-Live Model 600 */ | 1029 | { USB_DEVICE(0x0573, 0x2d00), .driver_info=HPG_WINTV_LIVE_PAL_BG }, |
105 | { USB_DEVICE(0x0573, 0x2101) }, /* Zoran Co. PMD (Nogatech) AV-grabber Manhattan */ | 1030 | { USB_DEVICE(0x0573, 0x2d01), .driver_info=HPG_WINTV_LIVE_PRO_NTSC_MN }, |
106 | { USB_DEVICE(0x0573, 0x4100) }, /* Nogatech USB-TV FM (NTSC) */ | 1031 | { USB_DEVICE(0x0573, 0x2101), .driver_info=ZORAN_PMD_NOGATECH }, |
107 | { USB_DEVICE(0x0573, 0x4110) }, /* PNY USB-TV (NTSC) FM */ | 1032 | { USB_DEVICE(0x0573, 0x4100), .driver_info=NOGATECH_USB_TV_NTSC_FM }, |
108 | { USB_DEVICE(0x0573, 0x4450) }, /* PixelView PlayTv-USB PRO (PAL) FM */ | 1033 | { USB_DEVICE(0x0573, 0x4110), .driver_info=PNY_USB_TV_NTSC_FM }, |
109 | { USB_DEVICE(0x0573, 0x4550) }, /* ZTV ZT-721 2.4GHz USB A/V Receiver */ | 1034 | { USB_DEVICE(0x0573, 0x4450), .driver_info=PV_PLAYTV_USB_PRO_PAL_FM }, |
110 | { USB_DEVICE(0x0573, 0x4d00) }, /* Hauppauge WinTv-USB USA */ | 1035 | { USB_DEVICE(0x0573, 0x4550), .driver_info=ZT_721 }, |
111 | { USB_DEVICE(0x0573, 0x4d01) }, /* Hauppauge WinTv-USB */ | 1036 | { USB_DEVICE(0x0573, 0x4d00), .driver_info=HPG_WINTV_NTSC_MN }, |
112 | { USB_DEVICE(0x0573, 0x4d02) }, /* Hauppauge WinTv-USB UK */ | 1037 | { USB_DEVICE(0x0573, 0x4d01), .driver_info=HPG_WINTV_PAL_BG }, |
113 | { USB_DEVICE(0x0573, 0x4d03) }, /* Hauppauge WinTv-USB France */ | 1038 | { USB_DEVICE(0x0573, 0x4d02), .driver_info=HPG_WINTV_PAL_I }, |
114 | { USB_DEVICE(0x0573, 0x4d10) }, /* Hauppauge WinTv-USB with FM USA radio */ | 1039 | { USB_DEVICE(0x0573, 0x4d03), .driver_info=HPG_WINTV_PAL_SECAM_L }, |
115 | { USB_DEVICE(0x0573, 0x4d11) }, /* Hauppauge WinTv-USB (PAL) with FM radio */ | 1040 | { USB_DEVICE(0x0573, 0x4d04), .driver_info=HPG_WINTV_PAL_D_K }, |
116 | { USB_DEVICE(0x0573, 0x4d12) }, /* Hauppauge WinTv-USB UK with FM Radio */ | 1041 | { USB_DEVICE(0x0573, 0x4d10), .driver_info=HPG_WINTV_NTSC_FM }, |
117 | { USB_DEVICE(0x0573, 0x4d2a) }, /* Hauppague WinTv USB Model 602 40201 Rev B285 */ | 1042 | { USB_DEVICE(0x0573, 0x4d11), .driver_info=HPG_WINTV_PAL_BG_FM }, |
118 | { USB_DEVICE(0x0573, 0x4d2b) }, /* Hauppague WinTv USB Model 602 40201 Rev B282 */ | 1043 | { USB_DEVICE(0x0573, 0x4d12), .driver_info=HPG_WINTV_PAL_I_FM }, |
119 | { USB_DEVICE(0x0573, 0x4d2c) }, /* Hauppague WinTv USB Model 40209 Rev. E1A5 PAL*/ | 1044 | { USB_DEVICE(0x0573, 0x4d14), .driver_info=HPG_WINTV_PAL_D_K_FM }, |
120 | { USB_DEVICE(0x0573, 0x4d20) }, /* Hauppauge WinTv-USB II (PAL) FM Model 40201 Rev B226 */ | 1045 | { USB_DEVICE(0x0573, 0x4d2a), .driver_info=HPG_WINTV_PRO_NTSC_MN }, |
121 | { USB_DEVICE(0x0573, 0x4d21) }, /* Hauppauge WinTv-USB II (PAL) with FM radio*/ | 1046 | { USB_DEVICE(0x0573, 0x4d2b), .driver_info=HPG_WINTV_PRO_NTSC_MN_V2 }, |
122 | { USB_DEVICE(0x0573, 0x4d22) }, /* Hauppauge WinTv-USB II (PAL) Model 566 */ | 1047 | { USB_DEVICE(0x0573, 0x4d2c), .driver_info=HPG_WINTV_PRO_PAL }, |
123 | { USB_DEVICE(0x0573, 0x4d23) }, /* Hauppauge WinTv-USB France 4D23*/ | 1048 | { USB_DEVICE(0x0573, 0x4d20), .driver_info=HPG_WINTV_PRO_NTSC_MN_V3 }, |
124 | { USB_DEVICE(0x0573, 0x4d25) }, /* Hauppauge WinTv-USB Model 40209 rev B234 */ | 1049 | { USB_DEVICE(0x0573, 0x4d21), .driver_info=HPG_WINTV_PRO_PAL_BG }, |
125 | { USB_DEVICE(0x0573, 0x4d26) }, /* Hauppauge WinTv-USB Model 40209 Rev B243 */ | 1050 | { USB_DEVICE(0x0573, 0x4d22), .driver_info=HPG_WINTV_PRO_PAL_I }, |
126 | { USB_DEVICE(0x0573, 0x4d27) }, /* Hauppauge WinTv-USB Model 40204 Rev B281 */ | 1051 | { USB_DEVICE(0x0573, 0x4d23), .driver_info=HPG_WINTV_PRO_PAL_SECAM_L }, |
127 | { USB_DEVICE(0x0573, 0x4d28) }, /* Hauppauge WinTv-USB Model 40204 Rev B283 */ | 1052 | { USB_DEVICE(0x0573, 0x4d24), .driver_info=HPG_WINTV_PRO_PAL_D_K }, |
128 | { USB_DEVICE(0x0573, 0x4d29) }, /* Hauppauge WinTv-USB Model 40205 Rev B298 */ | 1053 | { USB_DEVICE(0x0573, 0x4d25), .driver_info=HPG_WINTV_PRO_PAL_SECAM }, |
129 | { USB_DEVICE(0x0573, 0x4d30) }, /* Hauppauge WinTv-USB FM Model 40211 Rev B123 */ | 1054 | { USB_DEVICE(0x0573, 0x4d26), .driver_info=HPG_WINTV_PRO_PAL_SECAM_V2 }, |
130 | { USB_DEVICE(0x0573, 0x4d31) }, /* Hauppauge WinTv-USB III (PAL) with FM radio Model 568 */ | 1055 | { USB_DEVICE(0x0573, 0x4d27), .driver_info=HPG_WINTV_PRO_PAL_BG_V2 }, |
131 | { USB_DEVICE(0x0573, 0x4d32) }, /* Hauppauge WinTv-USB III (PAL) FM Model 573 */ | 1056 | { USB_DEVICE(0x0573, 0x4d28), .driver_info=HPG_WINTV_PRO_PAL_BG_D_K }, |
132 | { USB_DEVICE(0x0573, 0x4d35) }, /* Hauppauge WinTv-USB III (SECAM) FM Model 40219 Rev B252 */ | 1057 | { USB_DEVICE(0x0573, 0x4d29), .driver_info=HPG_WINTV_PRO_PAL_I_D_K }, |
133 | { USB_DEVICE(0x0573, 0x4d37) }, /* Hauppauge WinTv-USB Model 40219 Rev E189 */ | 1058 | { USB_DEVICE(0x0573, 0x4d30), .driver_info=HPG_WINTV_PRO_NTSC_MN_FM }, |
134 | { USB_DEVICE(0x0768, 0x0006) }, /* Camtel Technology USB TV Genie Pro FM Model TVB330 */ | 1059 | { USB_DEVICE(0x0573, 0x4d31), .driver_info=HPG_WINTV_PRO_PAL_BG_FM }, |
135 | { USB_DEVICE(0x07d0, 0x0001) }, /* Digital Video Creator I */ | 1060 | { USB_DEVICE(0x0573, 0x4d32), .driver_info=HPG_WINTV_PRO_PAL_I_FM }, |
136 | { USB_DEVICE(0x07d0, 0x0002) }, /* Global Village GV-007 (NTSC) */ | 1061 | { USB_DEVICE(0x0573, 0x4d34), .driver_info=HPG_WINTV_PRO_PAL_D_K_FM }, |
137 | { USB_DEVICE(0x07d0, 0x0003) }, /* Dazzle Fusion Model DVC-50 Rev 1 (NTSC) */ | 1062 | { USB_DEVICE(0x0573, 0x4d35), .driver_info=HPG_WINTV_PRO_TEMIC_PAL_FM }, |
138 | { USB_DEVICE(0x07d0, 0x0004) }, /* Dazzle Fusion Model DVC-80 Rev 1 (PAL) */ | 1063 | { USB_DEVICE(0x0573, 0x4d36), .driver_info=HPG_WINTV_PRO_TEMIC_PAL_BG_FM }, |
139 | { USB_DEVICE(0x07d0, 0x0005) }, /* Dazzle Fusion Model DVC-90 Rev 1 (SECAM) */ | 1064 | { USB_DEVICE(0x0573, 0x4d37), .driver_info=HPG_WINTV_PRO_PAL_FM }, |
140 | { USB_DEVICE(0x2304, 0x010d) }, /* Pinnacle Studio PCTV USB (PAL) */ | 1065 | { USB_DEVICE(0x0573, 0x4d38), .driver_info=HPG_WINTV_PRO_NTSC_MN_FM_V2 }, |
141 | { USB_DEVICE(0x2304, 0x0109) }, /* Pinnacle Studio PCTV USB (SECAM) */ | 1066 | { USB_DEVICE(0x0768, 0x0006), .driver_info=CAMTEL_TVB330 }, |
142 | { USB_DEVICE(0x2304, 0x0110) }, /* Pinnacle Studio PCTV USB (PAL) */ | 1067 | { USB_DEVICE(0x07d0, 0x0001), .driver_info=DIGITAL_VIDEO_CREATOR_I }, |
143 | { USB_DEVICE(0x2304, 0x0111) }, /* Miro PCTV USB */ | 1068 | { USB_DEVICE(0x07d0, 0x0002), .driver_info=GLOBAL_VILLAGE_GV_007_NTSC }, |
144 | { USB_DEVICE(0x2304, 0x0112) }, /* Pinnacle Studio PCTV USB (NTSC) with FM radio */ | 1069 | { USB_DEVICE(0x07d0, 0x0003), .driver_info=DAZZLE_DVC_50_REV_1_NTSC }, |
145 | { USB_DEVICE(0x2304, 0x0210) }, /* Pinnacle Studio PCTV USB (PAL) with FM radio */ | 1070 | { USB_DEVICE(0x07d0, 0x0004), .driver_info=DAZZLE_DVC_80_REV_1_PAL }, |
146 | { USB_DEVICE(0x2304, 0x0212) }, /* Pinnacle Studio PCTV USB (NTSC) with FM radio */ | 1071 | { USB_DEVICE(0x07d0, 0x0005), .driver_info=DAZZLE_DVC_90_REV_1_SECAM }, |
147 | { USB_DEVICE(0x2304, 0x0214) }, /* Pinnacle Studio PCTV USB (PAL) with FM radio */ | 1072 | { USB_DEVICE(0x07f8, 0x9104), .driver_info=ESKAPE_LABS_MYTV2GO }, |
148 | { USB_DEVICE(0x2304, 0x0300) }, /* Pinnacle Studio Linx Video input cable (NTSC) */ | 1073 | { USB_DEVICE(0x2304, 0x010d), .driver_info=PINNA_PCTV_USB_PAL }, |
149 | { USB_DEVICE(0x2304, 0x0301) }, /* Pinnacle Studio Linx Video input cable (PAL) */ | 1074 | { USB_DEVICE(0x2304, 0x0109), .driver_info=PINNA_PCTV_USB_SECAM }, |
150 | { USB_DEVICE(0x2304, 0x0419) }, /* Pinnacle PCTV Bungee USB (PAL) FM */ | 1075 | { USB_DEVICE(0x2304, 0x0110), .driver_info=PINNA_PCTV_USB_PAL_FM }, |
151 | { USB_DEVICE(0x2400, 0x4200) }, /* Hauppauge WinTv-USB2 Model 42012 */ | 1076 | { USB_DEVICE(0x2304, 0x0111), .driver_info=MIRO_PCTV_USB }, |
152 | 1077 | { USB_DEVICE(0x2304, 0x0112), .driver_info=PINNA_PCTV_USB_NTSC_FM }, | |
153 | { } /* Terminating entry */ | 1078 | { USB_DEVICE(0x2304, 0x0210), .driver_info=PINNA_PCTV_USB_PAL_FM_V2 }, |
1079 | { USB_DEVICE(0x2304, 0x0212), .driver_info=PINNA_PCTV_USB_NTSC_FM_V2 }, | ||
1080 | { USB_DEVICE(0x2304, 0x0214), .driver_info=PINNA_PCTV_USB_PAL_FM_V3 }, | ||
1081 | { USB_DEVICE(0x2304, 0x0300), .driver_info=PINNA_LINX_VD_IN_CAB_NTSC }, | ||
1082 | { USB_DEVICE(0x2304, 0x0301), .driver_info=PINNA_LINX_VD_IN_CAB_PAL }, | ||
1083 | { USB_DEVICE(0x2304, 0x0419), .driver_info=PINNA_PCTV_BUNGEE_PAL_FM }, | ||
1084 | { USB_DEVICE(0x2400, 0x4200), .driver_info=HPG_WINTV }, | ||
154 | }; | 1085 | }; |
155 | 1086 | ||
156 | MODULE_DEVICE_TABLE (usb, usbvision_table); | 1087 | MODULE_DEVICE_TABLE (usb, usbvision_table); |
diff --git a/drivers/media/video/usbvision/usbvision-cards.h b/drivers/media/video/usbvision/usbvision-cards.h new file mode 100644 index 000000000000..512c5cee4145 --- /dev/null +++ b/drivers/media/video/usbvision/usbvision-cards.h | |||
@@ -0,0 +1,66 @@ | |||
1 | #define XANBOO 0 | ||
2 | #define BELKIN_VIDEOBUS_II 1 | ||
3 | #define BELKIN_VIDEOBUS 2 | ||
4 | #define BELKIN_USB_VIDEOBUS_II 3 | ||
5 | #define ECHOFX_INTERVIEW_LITE 4 | ||
6 | #define USBGEAR_USBG_V1 5 | ||
7 | #define D_LINK_V100 6 | ||
8 | #define X10_USB_CAMERA 7 | ||
9 | #define HPG_WINTV_LIVE_PAL_BG 8 | ||
10 | #define HPG_WINTV_LIVE_PRO_NTSC_MN 9 | ||
11 | #define ZORAN_PMD_NOGATECH 10 | ||
12 | #define NOGATECH_USB_TV_NTSC_FM 11 | ||
13 | #define PNY_USB_TV_NTSC_FM 12 | ||
14 | #define PV_PLAYTV_USB_PRO_PAL_FM 13 | ||
15 | #define ZT_721 14 | ||
16 | #define HPG_WINTV_NTSC_MN 15 | ||
17 | #define HPG_WINTV_PAL_BG 16 | ||
18 | #define HPG_WINTV_PAL_I 17 | ||
19 | #define HPG_WINTV_PAL_SECAM_L 18 | ||
20 | #define HPG_WINTV_PAL_D_K 19 | ||
21 | #define HPG_WINTV_NTSC_FM 20 | ||
22 | #define HPG_WINTV_PAL_BG_FM 21 | ||
23 | #define HPG_WINTV_PAL_I_FM 22 | ||
24 | #define HPG_WINTV_PAL_D_K_FM 23 | ||
25 | #define HPG_WINTV_PRO_NTSC_MN 24 | ||
26 | #define HPG_WINTV_PRO_NTSC_MN_V2 25 | ||
27 | #define HPG_WINTV_PRO_PAL 26 | ||
28 | #define HPG_WINTV_PRO_NTSC_MN_V3 27 | ||
29 | #define HPG_WINTV_PRO_PAL_BG 28 | ||
30 | #define HPG_WINTV_PRO_PAL_I 29 | ||
31 | #define HPG_WINTV_PRO_PAL_SECAM_L 30 | ||
32 | #define HPG_WINTV_PRO_PAL_D_K 31 | ||
33 | #define HPG_WINTV_PRO_PAL_SECAM 32 | ||
34 | #define HPG_WINTV_PRO_PAL_SECAM_V2 33 | ||
35 | #define HPG_WINTV_PRO_PAL_BG_V2 34 | ||
36 | #define HPG_WINTV_PRO_PAL_BG_D_K 35 | ||
37 | #define HPG_WINTV_PRO_PAL_I_D_K 36 | ||
38 | #define HPG_WINTV_PRO_NTSC_MN_FM 37 | ||
39 | #define HPG_WINTV_PRO_PAL_BG_FM 38 | ||
40 | #define HPG_WINTV_PRO_PAL_I_FM 39 | ||
41 | #define HPG_WINTV_PRO_PAL_D_K_FM 40 | ||
42 | #define HPG_WINTV_PRO_TEMIC_PAL_FM 41 | ||
43 | #define HPG_WINTV_PRO_TEMIC_PAL_BG_FM 42 | ||
44 | #define HPG_WINTV_PRO_PAL_FM 43 | ||
45 | #define HPG_WINTV_PRO_NTSC_MN_FM_V2 44 | ||
46 | #define CAMTEL_TVB330 45 | ||
47 | #define DIGITAL_VIDEO_CREATOR_I 46 | ||
48 | #define GLOBAL_VILLAGE_GV_007_NTSC 47 | ||
49 | #define DAZZLE_DVC_50_REV_1_NTSC 48 | ||
50 | #define DAZZLE_DVC_80_REV_1_PAL 49 | ||
51 | #define DAZZLE_DVC_90_REV_1_SECAM 50 | ||
52 | #define ESKAPE_LABS_MYTV2GO 51 | ||
53 | #define PINNA_PCTV_USB_PAL 52 | ||
54 | #define PINNA_PCTV_USB_SECAM 53 | ||
55 | #define PINNA_PCTV_USB_PAL_FM 54 | ||
56 | #define MIRO_PCTV_USB 55 | ||
57 | #define PINNA_PCTV_USB_NTSC_FM 56 | ||
58 | #define PINNA_PCTV_USB_PAL_FM_V2 57 | ||
59 | #define PINNA_PCTV_USB_NTSC_FM_V2 58 | ||
60 | #define PINNA_PCTV_USB_PAL_FM_V3 59 | ||
61 | #define PINNA_LINX_VD_IN_CAB_NTSC 60 | ||
62 | #define PINNA_LINX_VD_IN_CAB_PAL 61 | ||
63 | #define PINNA_PCTV_BUNGEE_PAL_FM 62 | ||
64 | #define HPG_WINTV 63 | ||
65 | |||
66 | extern const int usbvision_device_data_size; | ||
diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c index f2154dc072e2..bcb551adb7e6 100644 --- a/drivers/media/video/usbvision/usbvision-core.c +++ b/drivers/media/video/usbvision/usbvision-core.c | |||
@@ -2040,8 +2040,8 @@ int usbvision_set_input(struct usb_usbvision *usbvision) | |||
2040 | return 0; | 2040 | return 0; |
2041 | 2041 | ||
2042 | /* Set input format expected from decoder*/ | 2042 | /* Set input format expected from decoder*/ |
2043 | if (usbvision_device_data[usbvision->DevModel].Vin_Reg1 >= 0) { | 2043 | if (usbvision_device_data[usbvision->DevModel].Vin_Reg1_override) { |
2044 | value[0] = usbvision_device_data[usbvision->DevModel].Vin_Reg1 & 0xff; | 2044 | value[0] = usbvision_device_data[usbvision->DevModel].Vin_Reg1; |
2045 | } else if(usbvision_device_data[usbvision->DevModel].Codec == CODEC_SAA7113) { | 2045 | } else if(usbvision_device_data[usbvision->DevModel].Codec == CODEC_SAA7113) { |
2046 | /* SAA7113 uses 8 bit output */ | 2046 | /* SAA7113 uses 8 bit output */ |
2047 | value[0] = USBVISION_8_422_SYNC; | 2047 | value[0] = USBVISION_8_422_SYNC; |
@@ -2112,8 +2112,8 @@ int usbvision_set_input(struct usb_usbvision *usbvision) | |||
2112 | 2112 | ||
2113 | dvi_yuv_value = 0x00; /* U comes after V, Ya comes after U/V, Yb comes after Yb */ | 2113 | dvi_yuv_value = 0x00; /* U comes after V, Ya comes after U/V, Yb comes after Yb */ |
2114 | 2114 | ||
2115 | if(usbvision_device_data[usbvision->DevModel].Dvi_yuv >= 0){ | 2115 | if(usbvision_device_data[usbvision->DevModel].Dvi_yuv_override){ |
2116 | dvi_yuv_value = usbvision_device_data[usbvision->DevModel].Dvi_yuv & 0xff; | 2116 | dvi_yuv_value = usbvision_device_data[usbvision->DevModel].Dvi_yuv; |
2117 | } | 2117 | } |
2118 | else if(usbvision_device_data[usbvision->DevModel].Codec == CODEC_SAA7113) { | 2118 | else if(usbvision_device_data[usbvision->DevModel].Codec == CODEC_SAA7113) { |
2119 | /* This changes as the fine sync control changes. Further investigation necessary */ | 2119 | /* This changes as the fine sync control changes. Further investigation necessary */ |
@@ -2238,7 +2238,7 @@ static void call_usbvision_power_off(struct work_struct *work) | |||
2238 | PDEBUG(DBG_FUNC, ""); | 2238 | PDEBUG(DBG_FUNC, ""); |
2239 | down_interruptible(&usbvision->lock); | 2239 | down_interruptible(&usbvision->lock); |
2240 | if(usbvision->user == 0) { | 2240 | if(usbvision->user == 0) { |
2241 | usbvision_i2c_usb_del_bus(&usbvision->i2c_adap); | 2241 | usbvision_i2c_unregister(usbvision); |
2242 | 2242 | ||
2243 | usbvision_power_off(usbvision); | 2243 | usbvision_power_off(usbvision); |
2244 | usbvision->initialized = 0; | 2244 | usbvision->initialized = 0; |
diff --git a/drivers/media/video/usbvision/usbvision-i2c.c b/drivers/media/video/usbvision/usbvision-i2c.c index 609e1fd9c784..025be555194f 100644 --- a/drivers/media/video/usbvision/usbvision-i2c.c +++ b/drivers/media/video/usbvision/usbvision-i2c.c | |||
@@ -1,8 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * I2C_ALGO_USB.C | 2 | * usbvision_i2c.c |
3 | * i2c algorithm for USB-I2C Bridges | 3 | * i2c algorithm for USB-I2C Bridges |
4 | * | 4 | * |
5 | * Copyright (c) 1999-2005 Joerg Heckenbach <joerg@heckenbach-aw.de> | 5 | * Copyright (c) 1999-2007 Joerg Heckenbach <joerg@heckenbach-aw.de> |
6 | * Dwaine Garden <dwainegarden@rogers.com> | 6 | * Dwaine Garden <dwainegarden@rogers.com> |
7 | * | 7 | * |
8 | * This module is part of usbvision driver project. | 8 | * This module is part of usbvision driver project. |
@@ -39,7 +39,6 @@ | |||
39 | #include "usbvision.h" | 39 | #include "usbvision.h" |
40 | 40 | ||
41 | #define DBG_I2C 1<<0 | 41 | #define DBG_I2C 1<<0 |
42 | #define DBG_ALGO 1<<1 | ||
43 | 42 | ||
44 | static int i2c_debug = 0; | 43 | static int i2c_debug = 0; |
45 | 44 | ||
@@ -49,22 +48,22 @@ MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); | |||
49 | #define PDEBUG(level, fmt, args...) \ | 48 | #define PDEBUG(level, fmt, args...) \ |
50 | if (i2c_debug & (level)) info("[%s:%d] " fmt, __PRETTY_FUNCTION__, __LINE__ , ## args) | 49 | if (i2c_debug & (level)) info("[%s:%d] " fmt, __PRETTY_FUNCTION__, __LINE__ , ## args) |
51 | 50 | ||
52 | static int usbvision_i2c_write(void *data, unsigned char addr, char *buf, | 51 | static int usbvision_i2c_write(struct usb_usbvision *usbvision, unsigned char addr, char *buf, |
53 | short len); | 52 | short len); |
54 | static int usbvision_i2c_read(void *data, unsigned char addr, char *buf, | 53 | static int usbvision_i2c_read(struct usb_usbvision *usbvision, unsigned char addr, char *buf, |
55 | short len); | 54 | short len); |
56 | 55 | ||
57 | static inline int try_write_address(struct i2c_adapter *i2c_adap, | 56 | static inline int try_write_address(struct i2c_adapter *i2c_adap, |
58 | unsigned char addr, int retries) | 57 | unsigned char addr, int retries) |
59 | { | 58 | { |
60 | void *data; | 59 | struct usb_usbvision *usbvision; |
61 | int i, ret = -1; | 60 | int i, ret = -1; |
62 | char buf[4]; | 61 | char buf[4]; |
63 | 62 | ||
64 | data = i2c_get_adapdata(i2c_adap); | 63 | usbvision = (struct usb_usbvision *)i2c_get_adapdata(i2c_adap); |
65 | buf[0] = 0x00; | 64 | buf[0] = 0x00; |
66 | for (i = 0; i <= retries; i++) { | 65 | for (i = 0; i <= retries; i++) { |
67 | ret = (usbvision_i2c_write(data, addr, buf, 1)); | 66 | ret = (usbvision_i2c_write(usbvision, addr, buf, 1)); |
68 | if (ret == 1) | 67 | if (ret == 1) |
69 | break; /* success! */ | 68 | break; /* success! */ |
70 | udelay(5); | 69 | udelay(5); |
@@ -73,8 +72,8 @@ static inline int try_write_address(struct i2c_adapter *i2c_adap, | |||
73 | udelay(10); | 72 | udelay(10); |
74 | } | 73 | } |
75 | if (i) { | 74 | if (i) { |
76 | PDEBUG(DBG_ALGO,"Needed %d retries for address %#2x", i, addr); | 75 | PDEBUG(DBG_I2C,"Needed %d retries for address %#2x", i, addr); |
77 | PDEBUG(DBG_ALGO,"Maybe there's no device at this address"); | 76 | PDEBUG(DBG_I2C,"Maybe there's no device at this address"); |
78 | } | 77 | } |
79 | return ret; | 78 | return ret; |
80 | } | 79 | } |
@@ -82,13 +81,13 @@ static inline int try_write_address(struct i2c_adapter *i2c_adap, | |||
82 | static inline int try_read_address(struct i2c_adapter *i2c_adap, | 81 | static inline int try_read_address(struct i2c_adapter *i2c_adap, |
83 | unsigned char addr, int retries) | 82 | unsigned char addr, int retries) |
84 | { | 83 | { |
85 | void *data; | 84 | struct usb_usbvision *usbvision; |
86 | int i, ret = -1; | 85 | int i, ret = -1; |
87 | char buf[4]; | 86 | char buf[4]; |
88 | 87 | ||
89 | data = i2c_get_adapdata(i2c_adap); | 88 | usbvision = (struct usb_usbvision *)i2c_get_adapdata(i2c_adap); |
90 | for (i = 0; i <= retries; i++) { | 89 | for (i = 0; i <= retries; i++) { |
91 | ret = (usbvision_i2c_read(data, addr, buf, 1)); | 90 | ret = (usbvision_i2c_read(usbvision, addr, buf, 1)); |
92 | if (ret == 1) | 91 | if (ret == 1) |
93 | break; /* success! */ | 92 | break; /* success! */ |
94 | udelay(5); | 93 | udelay(5); |
@@ -97,8 +96,8 @@ static inline int try_read_address(struct i2c_adapter *i2c_adap, | |||
97 | udelay(10); | 96 | udelay(10); |
98 | } | 97 | } |
99 | if (i) { | 98 | if (i) { |
100 | PDEBUG(DBG_ALGO,"Needed %d retries for address %#2x", i, addr); | 99 | PDEBUG(DBG_I2C,"Needed %d retries for address %#2x", i, addr); |
101 | PDEBUG(DBG_ALGO,"Maybe there's no device at this address"); | 100 | PDEBUG(DBG_I2C,"Maybe there's no device at this address"); |
102 | } | 101 | } |
103 | return ret; | 102 | return ret; |
104 | } | 103 | } |
@@ -152,32 +151,32 @@ static inline int usb_find_address(struct i2c_adapter *i2c_adap, | |||
152 | } | 151 | } |
153 | 152 | ||
154 | static int | 153 | static int |
155 | usb_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) | 154 | usbvision_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) |
156 | { | 155 | { |
157 | struct i2c_msg *pmsg; | 156 | struct i2c_msg *pmsg; |
158 | void *data; | 157 | struct usb_usbvision *usbvision; |
159 | int i, ret; | 158 | int i, ret; |
160 | unsigned char addr; | 159 | unsigned char addr; |
161 | 160 | ||
162 | data = i2c_get_adapdata(i2c_adap); | 161 | usbvision = (struct usb_usbvision *)i2c_get_adapdata(i2c_adap); |
163 | 162 | ||
164 | for (i = 0; i < num; i++) { | 163 | for (i = 0; i < num; i++) { |
165 | pmsg = &msgs[i]; | 164 | pmsg = &msgs[i]; |
166 | ret = usb_find_address(i2c_adap, pmsg, i2c_adap->retries, &addr); | 165 | ret = usb_find_address(i2c_adap, pmsg, i2c_adap->retries, &addr); |
167 | if (ret != 0) { | 166 | if (ret != 0) { |
168 | PDEBUG(DBG_ALGO,"got NAK from device, message #%d", i); | 167 | PDEBUG(DBG_I2C,"got NAK from device, message #%d", i); |
169 | return (ret < 0) ? ret : -EREMOTEIO; | 168 | return (ret < 0) ? ret : -EREMOTEIO; |
170 | } | 169 | } |
171 | 170 | ||
172 | if (pmsg->flags & I2C_M_RD) { | 171 | if (pmsg->flags & I2C_M_RD) { |
173 | /* read bytes into buffer */ | 172 | /* read bytes into buffer */ |
174 | ret = (usbvision_i2c_read(data, addr, pmsg->buf, pmsg->len)); | 173 | ret = (usbvision_i2c_read(usbvision, addr, pmsg->buf, pmsg->len)); |
175 | if (ret < pmsg->len) { | 174 | if (ret < pmsg->len) { |
176 | return (ret < 0) ? ret : -EREMOTEIO; | 175 | return (ret < 0) ? ret : -EREMOTEIO; |
177 | } | 176 | } |
178 | } else { | 177 | } else { |
179 | /* write bytes from buffer */ | 178 | /* write bytes from buffer */ |
180 | ret = (usbvision_i2c_write(data, addr, pmsg->buf, pmsg->len)); | 179 | ret = (usbvision_i2c_write(usbvision, addr, pmsg->buf, pmsg->len)); |
181 | if (ret < pmsg->len) { | 180 | if (ret < pmsg->len) { |
182 | return (ret < 0) ? ret : -EREMOTEIO; | 181 | return (ret < 0) ? ret : -EREMOTEIO; |
183 | } | 182 | } |
@@ -191,7 +190,7 @@ static int algo_control(struct i2c_adapter *adapter, unsigned int cmd, unsigned | |||
191 | return 0; | 190 | return 0; |
192 | } | 191 | } |
193 | 192 | ||
194 | static u32 usb_func(struct i2c_adapter *adap) | 193 | static u32 functionality(struct i2c_adapter *adap) |
195 | { | 194 | { |
196 | return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING; | 195 | return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING; |
197 | } | 196 | } |
@@ -199,11 +198,11 @@ static u32 usb_func(struct i2c_adapter *adap) | |||
199 | 198 | ||
200 | /* -----exported algorithm data: ------------------------------------- */ | 199 | /* -----exported algorithm data: ------------------------------------- */ |
201 | 200 | ||
202 | static struct i2c_algorithm i2c_usb_algo = { | 201 | static struct i2c_algorithm usbvision_algo = { |
203 | .master_xfer = usb_xfer, | 202 | .master_xfer = usbvision_i2c_xfer, |
204 | .smbus_xfer = NULL, | 203 | .smbus_xfer = NULL, |
205 | .algo_control = algo_control, | 204 | .algo_control = algo_control, |
206 | .functionality = usb_func, | 205 | .functionality = functionality, |
207 | }; | 206 | }; |
208 | 207 | ||
209 | 208 | ||
@@ -213,41 +212,29 @@ static struct i2c_algorithm i2c_usb_algo = { | |||
213 | static int usbvision_i2c_usb_add_bus(struct i2c_adapter *adap) | 212 | static int usbvision_i2c_usb_add_bus(struct i2c_adapter *adap) |
214 | { | 213 | { |
215 | PDEBUG(DBG_I2C, "I2C debugging is enabled [i2c]"); | 214 | PDEBUG(DBG_I2C, "I2C debugging is enabled [i2c]"); |
216 | PDEBUG(DBG_ALGO, "ALGO debugging is enabled [i2c]"); | 215 | PDEBUG(DBG_I2C, "ALGO debugging is enabled [i2c]"); |
217 | 216 | ||
218 | /* register new adapter to i2c module... */ | 217 | /* register new adapter to i2c module... */ |
219 | 218 | ||
220 | adap->algo = &i2c_usb_algo; | 219 | adap->algo = &usbvision_algo; |
221 | 220 | ||
222 | adap->timeout = 100; /* default values, should */ | 221 | adap->timeout = 100; /* default values, should */ |
223 | adap->retries = 3; /* be replaced by defines */ | 222 | adap->retries = 3; /* be replaced by defines */ |
224 | 223 | ||
225 | i2c_add_adapter(adap); | 224 | i2c_add_adapter(adap); |
226 | 225 | ||
227 | PDEBUG(DBG_ALGO,"i2c bus for %s registered", adap->name); | 226 | PDEBUG(DBG_I2C,"i2c bus for %s registered", adap->name); |
228 | |||
229 | return 0; | ||
230 | } | ||
231 | |||
232 | |||
233 | int usbvision_i2c_usb_del_bus(struct i2c_adapter *adap) | ||
234 | { | ||
235 | |||
236 | i2c_del_adapter(adap); | ||
237 | |||
238 | PDEBUG(DBG_ALGO,"i2c bus for %s unregistered", adap->name); | ||
239 | 227 | ||
240 | return 0; | 228 | return 0; |
241 | } | 229 | } |
242 | 230 | ||
243 | |||
244 | /* ----------------------------------------------------------------------- */ | 231 | /* ----------------------------------------------------------------------- */ |
245 | /* usbvision specific I2C functions */ | 232 | /* usbvision specific I2C functions */ |
246 | /* ----------------------------------------------------------------------- */ | 233 | /* ----------------------------------------------------------------------- */ |
247 | static struct i2c_adapter i2c_adap_template; | 234 | static struct i2c_adapter i2c_adap_template; |
248 | static struct i2c_client i2c_client_template; | 235 | static struct i2c_client i2c_client_template; |
249 | 236 | ||
250 | int usbvision_init_i2c(struct usb_usbvision *usbvision) | 237 | int usbvision_i2c_register(struct usb_usbvision *usbvision) |
251 | { | 238 | { |
252 | memcpy(&usbvision->i2c_adap, &i2c_adap_template, | 239 | memcpy(&usbvision->i2c_adap, &i2c_adap_template, |
253 | sizeof(struct i2c_adapter)); | 240 | sizeof(struct i2c_adapter)); |
@@ -265,7 +252,7 @@ int usbvision_init_i2c(struct usb_usbvision *usbvision) | |||
265 | usbvision->i2c_client.adapter = &usbvision->i2c_adap; | 252 | usbvision->i2c_client.adapter = &usbvision->i2c_adap; |
266 | 253 | ||
267 | if (usbvision_write_reg(usbvision, USBVISION_SER_MODE, USBVISION_IIC_LRNACK) < 0) { | 254 | if (usbvision_write_reg(usbvision, USBVISION_SER_MODE, USBVISION_IIC_LRNACK) < 0) { |
268 | printk(KERN_ERR "usbvision_init_i2c: can't write reg\n"); | 255 | printk(KERN_ERR "usbvision_register: can't write reg\n"); |
269 | return -EBUSY; | 256 | return -EBUSY; |
270 | } | 257 | } |
271 | 258 | ||
@@ -287,6 +274,16 @@ int usbvision_init_i2c(struct usb_usbvision *usbvision) | |||
287 | return usbvision_i2c_usb_add_bus(&usbvision->i2c_adap); | 274 | return usbvision_i2c_usb_add_bus(&usbvision->i2c_adap); |
288 | } | 275 | } |
289 | 276 | ||
277 | int usbvision_i2c_unregister(struct usb_usbvision *usbvision) | ||
278 | { | ||
279 | |||
280 | i2c_del_adapter(&(usbvision->i2c_adap)); | ||
281 | |||
282 | PDEBUG(DBG_I2C,"i2c bus for %s unregistered", usbvision->i2c_adap.name); | ||
283 | |||
284 | return 0; | ||
285 | } | ||
286 | |||
290 | void call_i2c_clients(struct usb_usbvision *usbvision, unsigned int cmd, | 287 | void call_i2c_clients(struct usb_usbvision *usbvision, unsigned int cmd, |
291 | void *arg) | 288 | void *arg) |
292 | { | 289 | { |
@@ -300,19 +297,12 @@ static int attach_inform(struct i2c_client *client) | |||
300 | usbvision = (struct usb_usbvision *)i2c_get_adapdata(client->adapter); | 297 | usbvision = (struct usb_usbvision *)i2c_get_adapdata(client->adapter); |
301 | 298 | ||
302 | switch (client->addr << 1) { | 299 | switch (client->addr << 1) { |
303 | case 0x43: | 300 | case 0x42 << 1: |
304 | case 0x4b: | 301 | case 0x43 << 1: |
305 | { | 302 | case 0x4a << 1: |
306 | struct tuner_setup tun_setup; | 303 | case 0x4b << 1: |
307 | 304 | PDEBUG(DBG_I2C,"attach_inform: tda9887 detected."); | |
308 | tun_setup.mode_mask = T_ANALOG_TV | T_RADIO; | ||
309 | tun_setup.type = TUNER_TDA9887; | ||
310 | tun_setup.addr = client->addr; | ||
311 | |||
312 | call_i2c_clients(usbvision, TUNER_SET_TYPE_ADDR, &tun_setup); | ||
313 | |||
314 | break; | 305 | break; |
315 | } | ||
316 | case 0x42: | 306 | case 0x42: |
317 | PDEBUG(DBG_I2C,"attach_inform: saa7114 detected."); | 307 | PDEBUG(DBG_I2C,"attach_inform: saa7114 detected."); |
318 | break; | 308 | break; |
@@ -480,7 +470,7 @@ static int usbvision_i2c_write_max4(struct usb_usbvision *usbvision, | |||
480 | return len; | 470 | return len; |
481 | } | 471 | } |
482 | 472 | ||
483 | static int usbvision_i2c_write(void *data, unsigned char addr, char *buf, | 473 | static int usbvision_i2c_write(struct usb_usbvision *usbvision, unsigned char addr, char *buf, |
484 | short len) | 474 | short len) |
485 | { | 475 | { |
486 | char *bufPtr = buf; | 476 | char *bufPtr = buf; |
@@ -488,7 +478,6 @@ static int usbvision_i2c_write(void *data, unsigned char addr, char *buf, | |||
488 | int wrcount = 0; | 478 | int wrcount = 0; |
489 | int count; | 479 | int count; |
490 | int maxLen = 4; | 480 | int maxLen = 4; |
491 | struct usb_usbvision *usbvision = (struct usb_usbvision *) data; | ||
492 | 481 | ||
493 | while (len > 0) { | 482 | while (len > 0) { |
494 | count = (len > maxLen) ? maxLen : len; | 483 | count = (len > maxLen) ? maxLen : len; |
@@ -503,14 +492,13 @@ static int usbvision_i2c_write(void *data, unsigned char addr, char *buf, | |||
503 | return wrcount; | 492 | return wrcount; |
504 | } | 493 | } |
505 | 494 | ||
506 | static int usbvision_i2c_read(void *data, unsigned char addr, char *buf, | 495 | static int usbvision_i2c_read(struct usb_usbvision *usbvision, unsigned char addr, char *buf, |
507 | short len) | 496 | short len) |
508 | { | 497 | { |
509 | char temp[4]; | 498 | char temp[4]; |
510 | int retval, i; | 499 | int retval, i; |
511 | int rdcount = 0; | 500 | int rdcount = 0; |
512 | int count; | 501 | int count; |
513 | struct usb_usbvision *usbvision = (struct usb_usbvision *) data; | ||
514 | 502 | ||
515 | while (len > 0) { | 503 | while (len > 0) { |
516 | count = (len > 3) ? 4 : len; | 504 | count = (len > 3) ? 4 : len; |
diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c index 6fc14557d623..216704170a4c 100644 --- a/drivers/media/video/usbvision/usbvision-video.c +++ b/drivers/media/video/usbvision/usbvision-video.c | |||
@@ -76,6 +76,7 @@ | |||
76 | #endif | 76 | #endif |
77 | 77 | ||
78 | #include "usbvision.h" | 78 | #include "usbvision.h" |
79 | #include "usbvision-cards.h" | ||
79 | 80 | ||
80 | #define DRIVER_AUTHOR "Joerg Heckenbach <joerg@heckenbach-aw.de>, Dwaine Garden <DwaineGarden@rogers.com>" | 81 | #define DRIVER_AUTHOR "Joerg Heckenbach <joerg@heckenbach-aw.de>, Dwaine Garden <DwaineGarden@rogers.com>" |
81 | #define DRIVER_NAME "usbvision" | 82 | #define DRIVER_NAME "usbvision" |
@@ -150,7 +151,6 @@ static int PowerOnAtOpen = 1; // Set the default device to power on at startu | |||
150 | static int video_nr = -1; // Sequential Number of Video Device | 151 | static int video_nr = -1; // Sequential Number of Video Device |
151 | static int radio_nr = -1; // Sequential Number of Radio Device | 152 | static int radio_nr = -1; // Sequential Number of Radio Device |
152 | static int vbi_nr = -1; // Sequential Number of VBI Device | 153 | static int vbi_nr = -1; // Sequential Number of VBI Device |
153 | static char *CustomDevice=NULL; // Set as nothing.... | ||
154 | 154 | ||
155 | // Grab parameters for the device driver | 155 | // Grab parameters for the device driver |
156 | 156 | ||
@@ -161,7 +161,6 @@ module_param(PowerOnAtOpen, int, 0444); | |||
161 | module_param(video_nr, int, 0444); | 161 | module_param(video_nr, int, 0444); |
162 | module_param(radio_nr, int, 0444); | 162 | module_param(radio_nr, int, 0444); |
163 | module_param(vbi_nr, int, 0444); | 163 | module_param(vbi_nr, int, 0444); |
164 | module_param(CustomDevice, charp, 0444); | ||
165 | #else // Old Style | 164 | #else // Old Style |
166 | MODULE_PARAM(isocMode, "i"); | 165 | MODULE_PARAM(isocMode, "i"); |
167 | MODULE_PARM(video_debug, "i"); // Grab the Debug Mode of the device driver | 166 | MODULE_PARM(video_debug, "i"); // Grab the Debug Mode of the device driver |
@@ -171,7 +170,6 @@ MODULE_PARM(SwitchSVideoInput, "i"); // To help people with Black and White ou | |||
171 | MODULE_PARM(video_nr, "i"); // video_nr option allows to specify a certain /dev/videoX device (like /dev/video0 or /dev/video1 ...) | 170 | MODULE_PARM(video_nr, "i"); // video_nr option allows to specify a certain /dev/videoX device (like /dev/video0 or /dev/video1 ...) |
172 | MODULE_PARM(radio_nr, "i"); // radio_nr option allows to specify a certain /dev/radioX device (like /dev/radio0 or /dev/radio1 ...) | 171 | MODULE_PARM(radio_nr, "i"); // radio_nr option allows to specify a certain /dev/radioX device (like /dev/radio0 or /dev/radio1 ...) |
173 | MODULE_PARM(vbi_nr, "i"); // vbi_nr option allows to specify a certain /dev/vbiX device (like /dev/vbi0 or /dev/vbi1 ...) | 172 | MODULE_PARM(vbi_nr, "i"); // vbi_nr option allows to specify a certain /dev/vbiX device (like /dev/vbi0 or /dev/vbi1 ...) |
174 | MODULE_PARM(CustomDevice, "s"); // .... CustomDevice | ||
175 | #endif | 173 | #endif |
176 | 174 | ||
177 | MODULE_PARM_DESC(isocMode, " Set the default format for ISOC endpoint. Default: 0x60 (Compression On)"); | 175 | MODULE_PARM_DESC(isocMode, " Set the default format for ISOC endpoint. Default: 0x60 (Compression On)"); |
@@ -180,7 +178,6 @@ MODULE_PARM_DESC(PowerOnAtOpen, " Set the default device to power on when device | |||
180 | MODULE_PARM_DESC(video_nr, "Set video device number (/dev/videoX). Default: -1 (autodetect)"); | 178 | MODULE_PARM_DESC(video_nr, "Set video device number (/dev/videoX). Default: -1 (autodetect)"); |
181 | MODULE_PARM_DESC(radio_nr, "Set radio device number (/dev/radioX). Default: -1 (autodetect)"); | 179 | MODULE_PARM_DESC(radio_nr, "Set radio device number (/dev/radioX). Default: -1 (autodetect)"); |
182 | MODULE_PARM_DESC(vbi_nr, "Set vbi device number (/dev/vbiX). Default: -1 (autodetect)"); | 180 | MODULE_PARM_DESC(vbi_nr, "Set vbi device number (/dev/vbiX). Default: -1 (autodetect)"); |
183 | MODULE_PARM_DESC(CustomDevice, " Define the fine tuning parameters for the device. Default: null"); | ||
184 | 181 | ||
185 | 182 | ||
186 | // Misc stuff | 183 | // Misc stuff |
@@ -409,7 +406,7 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file) | |||
409 | down(&usbvision->lock); | 406 | down(&usbvision->lock); |
410 | if (usbvision->power == 0) { | 407 | if (usbvision->power == 0) { |
411 | usbvision_power_on(usbvision); | 408 | usbvision_power_on(usbvision); |
412 | usbvision_init_i2c(usbvision); | 409 | usbvision_i2c_register(usbvision); |
413 | } | 410 | } |
414 | 411 | ||
415 | /* Send init sequence only once, it's large! */ | 412 | /* Send init sequence only once, it's large! */ |
@@ -431,7 +428,7 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file) | |||
431 | } | 428 | } |
432 | else { | 429 | else { |
433 | if (PowerOnAtOpen) { | 430 | if (PowerOnAtOpen) { |
434 | usbvision_i2c_usb_del_bus(&usbvision->i2c_adap); | 431 | usbvision_i2c_unregister(usbvision); |
435 | usbvision_power_off(usbvision); | 432 | usbvision_power_off(usbvision); |
436 | usbvision->initialized = 0; | 433 | usbvision->initialized = 0; |
437 | } | 434 | } |
@@ -1239,7 +1236,7 @@ static int usbvision_radio_open(struct inode *inode, struct file *file) | |||
1239 | usbvision_reset_powerOffTimer(usbvision); | 1236 | usbvision_reset_powerOffTimer(usbvision); |
1240 | if (usbvision->power == 0) { | 1237 | if (usbvision->power == 0) { |
1241 | usbvision_power_on(usbvision); | 1238 | usbvision_power_on(usbvision); |
1242 | usbvision_init_i2c(usbvision); | 1239 | usbvision_i2c_register(usbvision); |
1243 | } | 1240 | } |
1244 | } | 1241 | } |
1245 | 1242 | ||
@@ -1261,7 +1258,7 @@ static int usbvision_radio_open(struct inode *inode, struct file *file) | |||
1261 | 1258 | ||
1262 | if (errCode) { | 1259 | if (errCode) { |
1263 | if (PowerOnAtOpen) { | 1260 | if (PowerOnAtOpen) { |
1264 | usbvision_i2c_usb_del_bus(&usbvision->i2c_adap); | 1261 | usbvision_i2c_unregister(usbvision); |
1265 | usbvision_power_off(usbvision); | 1262 | usbvision_power_off(usbvision); |
1266 | usbvision->initialized = 0; | 1263 | usbvision->initialized = 0; |
1267 | } | 1264 | } |
@@ -1744,8 +1741,8 @@ static void usbvision_configure_video(struct usb_usbvision *usbvision) | |||
1744 | model = usbvision->DevModel; | 1741 | model = usbvision->DevModel; |
1745 | usbvision->palette = usbvision_v4l2_format[2]; // V4L2_PIX_FMT_RGB24; | 1742 | usbvision->palette = usbvision_v4l2_format[2]; // V4L2_PIX_FMT_RGB24; |
1746 | 1743 | ||
1747 | if (usbvision_device_data[usbvision->DevModel].Vin_Reg2 >= 0) { | 1744 | if (usbvision_device_data[usbvision->DevModel].Vin_Reg2_override) { |
1748 | usbvision->Vin_Reg2_Preset = usbvision_device_data[usbvision->DevModel].Vin_Reg2 & 0xff; | 1745 | usbvision->Vin_Reg2_Preset = usbvision_device_data[usbvision->DevModel].Vin_Reg2; |
1749 | } else { | 1746 | } else { |
1750 | usbvision->Vin_Reg2_Preset = 0; | 1747 | usbvision->Vin_Reg2_Preset = 0; |
1751 | } | 1748 | } |
@@ -1764,7 +1761,7 @@ static void usbvision_configure_video(struct usb_usbvision *usbvision) | |||
1764 | usbvision_audio_off(usbvision); //first switch off audio | 1761 | usbvision_audio_off(usbvision); //first switch off audio |
1765 | if (!PowerOnAtOpen) { | 1762 | if (!PowerOnAtOpen) { |
1766 | usbvision_power_on(usbvision); //and then power up the noisy tuner | 1763 | usbvision_power_on(usbvision); //and then power up the noisy tuner |
1767 | usbvision_init_i2c(usbvision); | 1764 | usbvision_i2c_register(usbvision); |
1768 | } | 1765 | } |
1769 | } | 1766 | } |
1770 | 1767 | ||
@@ -1775,7 +1772,8 @@ static void usbvision_configure_video(struct usb_usbvision *usbvision) | |||
1775 | * if it looks like USBVISION video device | 1772 | * if it looks like USBVISION video device |
1776 | * | 1773 | * |
1777 | */ | 1774 | */ |
1778 | static int __devinit usbvision_probe(struct usb_interface *intf, const struct usb_device_id *devid) | 1775 | static int __devinit usbvision_probe(struct usb_interface *intf, |
1776 | const struct usb_device_id *devid) | ||
1779 | { | 1777 | { |
1780 | struct usb_device *dev = usb_get_dev(interface_to_usbdev(intf)); | 1778 | struct usb_device *dev = usb_get_dev(interface_to_usbdev(intf)); |
1781 | struct usb_interface *uif; | 1779 | struct usb_interface *uif; |
@@ -1786,25 +1784,17 @@ static int __devinit usbvision_probe(struct usb_interface *intf, const struct us | |||
1786 | int model,i; | 1784 | int model,i; |
1787 | 1785 | ||
1788 | PDEBUG(DBG_PROBE, "VID=%#04x, PID=%#04x, ifnum=%u", | 1786 | PDEBUG(DBG_PROBE, "VID=%#04x, PID=%#04x, ifnum=%u", |
1789 | dev->descriptor.idVendor, dev->descriptor.idProduct, ifnum); | 1787 | dev->descriptor.idVendor, |
1788 | dev->descriptor.idProduct, ifnum); | ||
1790 | 1789 | ||
1791 | /* Is it an USBVISION video dev? */ | 1790 | model = devid->driver_info; |
1792 | model = 0; | 1791 | if ( (model<0) || (model>=usbvision_device_data_size) ) { |
1793 | for(model = 0; usbvision_device_data[model].idVendor; model++) { | 1792 | PDEBUG(DBG_PROBE, "model out of bounds %d",model); |
1794 | if (le16_to_cpu(dev->descriptor.idVendor) != usbvision_device_data[model].idVendor) { | 1793 | return -ENODEV; |
1795 | continue; | ||
1796 | } | ||
1797 | if (le16_to_cpu(dev->descriptor.idProduct) != usbvision_device_data[model].idProduct) { | ||
1798 | continue; | ||
1799 | } | ||
1800 | |||
1801 | printk(KERN_INFO "%s: %s found\n", __FUNCTION__, usbvision_device_data[model].ModelString); | ||
1802 | break; | ||
1803 | } | 1794 | } |
1795 | printk(KERN_INFO "%s: %s found\n", __FUNCTION__, | ||
1796 | usbvision_device_data[model].ModelString); | ||
1804 | 1797 | ||
1805 | if (usbvision_device_data[model].idVendor == 0) { | ||
1806 | return -ENODEV; //no matching device | ||
1807 | } | ||
1808 | if (usbvision_device_data[model].Interface >= 0) { | 1798 | if (usbvision_device_data[model].Interface >= 0) { |
1809 | interface = &dev->actconfig->interface[usbvision_device_data[model].Interface]->altsetting[0]; | 1799 | interface = &dev->actconfig->interface[usbvision_device_data[model].Interface]->altsetting[0]; |
1810 | } | 1800 | } |
@@ -1822,16 +1812,15 @@ static int __devinit usbvision_probe(struct usb_interface *intf, const struct us | |||
1822 | return -ENODEV; | 1812 | return -ENODEV; |
1823 | } | 1813 | } |
1824 | 1814 | ||
1825 | usb_get_dev(dev); | ||
1826 | |||
1827 | if ((usbvision = usbvision_alloc(dev)) == NULL) { | 1815 | if ((usbvision = usbvision_alloc(dev)) == NULL) { |
1828 | err("%s: couldn't allocate USBVision struct", __FUNCTION__); | 1816 | err("%s: couldn't allocate USBVision struct", __FUNCTION__); |
1829 | return -ENOMEM; | 1817 | return -ENOMEM; |
1830 | } | 1818 | } |
1819 | |||
1831 | if (dev->descriptor.bNumConfigurations > 1) { | 1820 | if (dev->descriptor.bNumConfigurations > 1) { |
1832 | usbvision->bridgeType = BRIDGE_NT1004; | 1821 | usbvision->bridgeType = BRIDGE_NT1004; |
1833 | } | 1822 | } |
1834 | else if (usbvision_device_data[model].ModelString == "Dazzle Fusion Model DVC-90 Rev 1 (SECAM)") { | 1823 | else if (model == DAZZLE_DVC_90_REV_1_SECAM) { |
1835 | usbvision->bridgeType = BRIDGE_NT1005; | 1824 | usbvision->bridgeType = BRIDGE_NT1005; |
1836 | } | 1825 | } |
1837 | else { | 1826 | else { |
@@ -1920,7 +1909,7 @@ static void __devexit usbvision_disconnect(struct usb_interface *intf) | |||
1920 | usbvision_stop_isoc(usbvision); | 1909 | usbvision_stop_isoc(usbvision); |
1921 | 1910 | ||
1922 | if (usbvision->power) { | 1911 | if (usbvision->power) { |
1923 | usbvision_i2c_usb_del_bus(&usbvision->i2c_adap); | 1912 | usbvision_i2c_unregister(usbvision); |
1924 | usbvision_power_off(usbvision); | 1913 | usbvision_power_off(usbvision); |
1925 | } | 1914 | } |
1926 | usbvision->remove_pending = 1; // Now all ISO data will be ignored | 1915 | usbvision->remove_pending = 1; // Now all ISO data will be ignored |
@@ -1951,124 +1940,6 @@ static struct usb_driver usbvision_driver = { | |||
1951 | }; | 1940 | }; |
1952 | 1941 | ||
1953 | /* | 1942 | /* |
1954 | * customdevice_process() | ||
1955 | * | ||
1956 | * This procedure preprocesses CustomDevice parameter if any | ||
1957 | * | ||
1958 | */ | ||
1959 | static void customdevice_process(void) | ||
1960 | { | ||
1961 | usbvision_device_data[0]=usbvision_device_data[1]; | ||
1962 | usbvision_table[0]=usbvision_table[1]; | ||
1963 | |||
1964 | if(CustomDevice) | ||
1965 | { | ||
1966 | char *parse=CustomDevice; | ||
1967 | |||
1968 | PDEBUG(DBG_PROBE, "CustomDevide=%s", CustomDevice); | ||
1969 | |||
1970 | /*format is CustomDevice="0x0573 0x4D31 0 7113 3 PAL 1 1 1 5 -1 -1 -1 -1 -1" | ||
1971 | usbvision_device_data[0].idVendor; | ||
1972 | usbvision_device_data[0].idProduct; | ||
1973 | usbvision_device_data[0].Interface; | ||
1974 | usbvision_device_data[0].Codec; | ||
1975 | usbvision_device_data[0].VideoChannels; | ||
1976 | usbvision_device_data[0].VideoNorm; | ||
1977 | usbvision_device_data[0].AudioChannels; | ||
1978 | usbvision_device_data[0].Radio; | ||
1979 | usbvision_device_data[0].Tuner; | ||
1980 | usbvision_device_data[0].TunerType; | ||
1981 | usbvision_device_data[0].Vin_Reg1; | ||
1982 | usbvision_device_data[0].Vin_Reg2; | ||
1983 | usbvision_device_data[0].X_Offset; | ||
1984 | usbvision_device_data[0].Y_Offset; | ||
1985 | usbvision_device_data[0].Dvi_yuv; | ||
1986 | usbvision_device_data[0].ModelString; | ||
1987 | */ | ||
1988 | |||
1989 | rmspace(parse); | ||
1990 | usbvision_device_data[0].ModelString="USBVISION Custom Device"; | ||
1991 | |||
1992 | parse+=2; | ||
1993 | sscanf(parse,"%x",&usbvision_device_data[0].idVendor); | ||
1994 | goto2next(parse); | ||
1995 | PDEBUG(DBG_PROBE, "idVendor=0x%.4X", usbvision_device_data[0].idVendor); | ||
1996 | parse+=2; | ||
1997 | sscanf(parse,"%x",&usbvision_device_data[0].idProduct); | ||
1998 | goto2next(parse); | ||
1999 | PDEBUG(DBG_PROBE, "idProduct=0x%.4X", usbvision_device_data[0].idProduct); | ||
2000 | sscanf(parse,"%d",&usbvision_device_data[0].Interface); | ||
2001 | goto2next(parse); | ||
2002 | PDEBUG(DBG_PROBE, "Interface=%d", usbvision_device_data[0].Interface); | ||
2003 | sscanf(parse,"%d",&usbvision_device_data[0].Codec); | ||
2004 | goto2next(parse); | ||
2005 | PDEBUG(DBG_PROBE, "Codec=%d", usbvision_device_data[0].Codec); | ||
2006 | sscanf(parse,"%d",&usbvision_device_data[0].VideoChannels); | ||
2007 | goto2next(parse); | ||
2008 | PDEBUG(DBG_PROBE, "VideoChannels=%d", usbvision_device_data[0].VideoChannels); | ||
2009 | |||
2010 | switch(*parse) | ||
2011 | { | ||
2012 | case 'P': | ||
2013 | PDEBUG(DBG_PROBE, "VideoNorm=PAL"); | ||
2014 | usbvision_device_data[0].VideoNorm=V4L2_STD_PAL; | ||
2015 | break; | ||
2016 | |||
2017 | case 'S': | ||
2018 | PDEBUG(DBG_PROBE, "VideoNorm=SECAM"); | ||
2019 | usbvision_device_data[0].VideoNorm=V4L2_STD_SECAM; | ||
2020 | break; | ||
2021 | |||
2022 | case 'N': | ||
2023 | PDEBUG(DBG_PROBE, "VideoNorm=NTSC"); | ||
2024 | usbvision_device_data[0].VideoNorm=V4L2_STD_NTSC; | ||
2025 | break; | ||
2026 | |||
2027 | default: | ||
2028 | PDEBUG(DBG_PROBE, "VideoNorm=PAL (by default)"); | ||
2029 | usbvision_device_data[0].VideoNorm=V4L2_STD_PAL; | ||
2030 | break; | ||
2031 | } | ||
2032 | goto2next(parse); | ||
2033 | |||
2034 | sscanf(parse,"%d",&usbvision_device_data[0].AudioChannels); | ||
2035 | goto2next(parse); | ||
2036 | PDEBUG(DBG_PROBE, "AudioChannels=%d", usbvision_device_data[0].AudioChannels); | ||
2037 | sscanf(parse,"%d",&usbvision_device_data[0].Radio); | ||
2038 | goto2next(parse); | ||
2039 | PDEBUG(DBG_PROBE, "Radio=%d", usbvision_device_data[0].Radio); | ||
2040 | sscanf(parse,"%d",&usbvision_device_data[0].Tuner); | ||
2041 | goto2next(parse); | ||
2042 | PDEBUG(DBG_PROBE, "Tuner=%d", usbvision_device_data[0].Tuner); | ||
2043 | sscanf(parse,"%d",&usbvision_device_data[0].TunerType); | ||
2044 | goto2next(parse); | ||
2045 | PDEBUG(DBG_PROBE, "TunerType=%d", usbvision_device_data[0].TunerType); | ||
2046 | sscanf(parse,"%d",&usbvision_device_data[0].Vin_Reg1); | ||
2047 | goto2next(parse); | ||
2048 | PDEBUG(DBG_PROBE, "Vin_Reg1=%d", usbvision_device_data[0].Vin_Reg1); | ||
2049 | sscanf(parse,"%d",&usbvision_device_data[0].Vin_Reg2); | ||
2050 | goto2next(parse); | ||
2051 | PDEBUG(DBG_PROBE, "Vin_Reg2=%d", usbvision_device_data[0].Vin_Reg2); | ||
2052 | sscanf(parse,"%d",&usbvision_device_data[0].X_Offset); | ||
2053 | goto2next(parse); | ||
2054 | PDEBUG(DBG_PROBE, "X_Offset=%d", usbvision_device_data[0].X_Offset); | ||
2055 | sscanf(parse,"%d",&usbvision_device_data[0].Y_Offset); | ||
2056 | goto2next(parse); | ||
2057 | PDEBUG(DBG_PROBE, "Y_Offset=%d", usbvision_device_data[0].Y_Offset); | ||
2058 | sscanf(parse,"%d",&usbvision_device_data[0].Dvi_yuv); | ||
2059 | PDEBUG(DBG_PROBE, "Dvi_yuv=%d", usbvision_device_data[0].Dvi_yuv); | ||
2060 | |||
2061 | //add to usbvision_table also | ||
2062 | usbvision_table[0].match_flags=USB_DEVICE_ID_MATCH_DEVICE; | ||
2063 | usbvision_table[0].idVendor=usbvision_device_data[0].idVendor; | ||
2064 | usbvision_table[0].idProduct=usbvision_device_data[0].idProduct; | ||
2065 | |||
2066 | } | ||
2067 | } | ||
2068 | |||
2069 | |||
2070 | |||
2071 | /* | ||
2072 | * usbvision_init() | 1943 | * usbvision_init() |
2073 | * | 1944 | * |
2074 | * This code is run to initialize the driver. | 1945 | * This code is run to initialize the driver. |
@@ -2092,8 +1963,6 @@ static int __init usbvision_init(void) | |||
2092 | usbvision_v4l2_format[7].supported = 0; // V4L2_PIX_FMT_YUV422P | 1963 | usbvision_v4l2_format[7].supported = 0; // V4L2_PIX_FMT_YUV422P |
2093 | } | 1964 | } |
2094 | 1965 | ||
2095 | customdevice_process(); | ||
2096 | |||
2097 | errCode = usb_register(&usbvision_driver); | 1966 | errCode = usb_register(&usbvision_driver); |
2098 | 1967 | ||
2099 | if (errCode == 0) { | 1968 | if (errCode == 0) { |
diff --git a/drivers/media/video/usbvision/usbvision.h b/drivers/media/video/usbvision/usbvision.h index ad6afd3e42a4..bd6f6422ed54 100644 --- a/drivers/media/video/usbvision/usbvision.h +++ b/drivers/media/video/usbvision/usbvision.h | |||
@@ -342,23 +342,24 @@ struct usbvision_frame { | |||
342 | #define BRIDGE_NT1005 1005 | 342 | #define BRIDGE_NT1005 1005 |
343 | 343 | ||
344 | struct usbvision_device_data_st { | 344 | struct usbvision_device_data_st { |
345 | int idVendor; | ||
346 | int idProduct; | ||
347 | int Interface; /* to handle special interface number like BELKIN and Hauppauge WinTV-USB II */ | ||
348 | int Codec; | ||
349 | int VideoChannels; | ||
350 | __u64 VideoNorm; | 345 | __u64 VideoNorm; |
351 | int AudioChannels; | 346 | const char *ModelString; |
352 | int Radio; | 347 | int Interface; /* to handle special interface number like BELKIN and Hauppauge WinTV-USB II */ |
353 | int vbi; | 348 | __u16 Codec; |
354 | int Tuner; | 349 | unsigned VideoChannels:3; |
355 | int TunerType; | 350 | unsigned AudioChannels:2; |
356 | int Vin_Reg1; | 351 | unsigned Radio:1; |
357 | int Vin_Reg2; | 352 | unsigned vbi:1; |
358 | int X_Offset; | 353 | unsigned Tuner:1; |
359 | int Y_Offset; | 354 | unsigned Vin_Reg1_override:1; /* Override default value with */ |
360 | int Dvi_yuv; | 355 | unsigned Vin_Reg2_override:1; /* Vin_Reg1, Vin_Reg2, etc. */ |
361 | char *ModelString; | 356 | unsigned Dvi_yuv_override:1; |
357 | __u8 Vin_Reg1; | ||
358 | __u8 Vin_Reg2; | ||
359 | __u8 Dvi_yuv; | ||
360 | __u8 TunerType; | ||
361 | __s16 X_Offset; | ||
362 | __s16 Y_Offset; | ||
362 | }; | 363 | }; |
363 | 364 | ||
364 | /* Declared on usbvision-cards.c */ | 365 | /* Declared on usbvision-cards.c */ |
@@ -481,13 +482,11 @@ struct usb_usbvision { | |||
481 | /* i2c-algo-usb declaration */ | 482 | /* i2c-algo-usb declaration */ |
482 | /* --------------------------------------------------------------- */ | 483 | /* --------------------------------------------------------------- */ |
483 | 484 | ||
484 | int usbvision_i2c_usb_del_bus(struct i2c_adapter *); | ||
485 | |||
486 | |||
487 | /* ----------------------------------------------------------------------- */ | 485 | /* ----------------------------------------------------------------------- */ |
488 | /* usbvision specific I2C functions */ | 486 | /* usbvision specific I2C functions */ |
489 | /* ----------------------------------------------------------------------- */ | 487 | /* ----------------------------------------------------------------------- */ |
490 | int usbvision_init_i2c(struct usb_usbvision *usbvision); | 488 | int usbvision_i2c_register(struct usb_usbvision *usbvision); |
489 | int usbvision_i2c_unregister(struct usb_usbvision *usbvision); | ||
491 | void call_i2c_clients(struct usb_usbvision *usbvision, unsigned int cmd,void *arg); | 490 | void call_i2c_clients(struct usb_usbvision *usbvision, unsigned int cmd,void *arg); |
492 | 491 | ||
493 | /* defined in usbvision-core.c */ | 492 | /* defined in usbvision-core.c */ |
diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c index 54747606eae1..49f1df74aa21 100644 --- a/drivers/media/video/v4l2-common.c +++ b/drivers/media/video/v4l2-common.c | |||
@@ -60,6 +60,7 @@ | |||
60 | #include <linux/video_decoder.h> | 60 | #include <linux/video_decoder.h> |
61 | #define __OLD_VIDIOC_ /* To allow fixing old calls*/ | 61 | #define __OLD_VIDIOC_ /* To allow fixing old calls*/ |
62 | #include <media/v4l2-common.h> | 62 | #include <media/v4l2-common.h> |
63 | #include <media/v4l2-chip-ident.h> | ||
63 | 64 | ||
64 | #ifdef CONFIG_KMOD | 65 | #ifdef CONFIG_KMOD |
65 | #include <linux/kmod.h> | 66 | #include <linux/kmod.h> |
@@ -260,6 +261,8 @@ char *v4l2_field_names[] = { | |||
260 | [V4L2_FIELD_SEQ_TB] = "seq-tb", | 261 | [V4L2_FIELD_SEQ_TB] = "seq-tb", |
261 | [V4L2_FIELD_SEQ_BT] = "seq-bt", | 262 | [V4L2_FIELD_SEQ_BT] = "seq-bt", |
262 | [V4L2_FIELD_ALTERNATE] = "alternate", | 263 | [V4L2_FIELD_ALTERNATE] = "alternate", |
264 | [V4L2_FIELD_INTERLACED_TB] = "interlaced-tb", | ||
265 | [V4L2_FIELD_INTERLACED_BT] = "interlaced-bt", | ||
263 | }; | 266 | }; |
264 | 267 | ||
265 | char *v4l2_type_names[] = { | 268 | char *v4l2_type_names[] = { |
@@ -269,7 +272,8 @@ char *v4l2_type_names[] = { | |||
269 | [V4L2_BUF_TYPE_VBI_CAPTURE] = "vbi-cap", | 272 | [V4L2_BUF_TYPE_VBI_CAPTURE] = "vbi-cap", |
270 | [V4L2_BUF_TYPE_VBI_OUTPUT] = "vbi-out", | 273 | [V4L2_BUF_TYPE_VBI_OUTPUT] = "vbi-out", |
271 | [V4L2_BUF_TYPE_SLICED_VBI_CAPTURE] = "sliced-vbi-cap", | 274 | [V4L2_BUF_TYPE_SLICED_VBI_CAPTURE] = "sliced-vbi-cap", |
272 | [V4L2_BUF_TYPE_SLICED_VBI_OUTPUT] = "slicec-vbi-out", | 275 | [V4L2_BUF_TYPE_SLICED_VBI_OUTPUT] = "sliced-vbi-out", |
276 | [V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY] = "video-out-over", | ||
273 | }; | 277 | }; |
274 | 278 | ||
275 | 279 | ||
@@ -380,6 +384,8 @@ static const char *v4l2_ioctls[] = { | |||
380 | 384 | ||
381 | [_IOC_NR(VIDIOC_DBG_S_REGISTER)] = "VIDIOC_DBG_S_REGISTER", | 385 | [_IOC_NR(VIDIOC_DBG_S_REGISTER)] = "VIDIOC_DBG_S_REGISTER", |
382 | [_IOC_NR(VIDIOC_DBG_G_REGISTER)] = "VIDIOC_DBG_G_REGISTER", | 386 | [_IOC_NR(VIDIOC_DBG_G_REGISTER)] = "VIDIOC_DBG_G_REGISTER", |
387 | |||
388 | [_IOC_NR(VIDIOC_G_CHIP_IDENT)] = "VIDIOC_G_CHIP_IDENT", | ||
383 | #endif | 389 | #endif |
384 | }; | 390 | }; |
385 | #define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls) | 391 | #define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls) |
@@ -410,14 +416,16 @@ static const char *v4l2_int_ioctls[] = { | |||
410 | [_IOC_NR(VIDIOC_INT_DECODE_VBI_LINE)] = "VIDIOC_INT_DECODE_VBI_LINE", | 416 | [_IOC_NR(VIDIOC_INT_DECODE_VBI_LINE)] = "VIDIOC_INT_DECODE_VBI_LINE", |
411 | [_IOC_NR(VIDIOC_INT_S_VBI_DATA)] = "VIDIOC_INT_S_VBI_DATA", | 417 | [_IOC_NR(VIDIOC_INT_S_VBI_DATA)] = "VIDIOC_INT_S_VBI_DATA", |
412 | [_IOC_NR(VIDIOC_INT_G_VBI_DATA)] = "VIDIOC_INT_G_VBI_DATA", | 418 | [_IOC_NR(VIDIOC_INT_G_VBI_DATA)] = "VIDIOC_INT_G_VBI_DATA", |
413 | [_IOC_NR(VIDIOC_INT_G_CHIP_IDENT)] = "VIDIOC_INT_G_CHIP_IDENT", | ||
414 | [_IOC_NR(VIDIOC_INT_I2S_CLOCK_FREQ)] = "VIDIOC_INT_I2S_CLOCK_FREQ", | 419 | [_IOC_NR(VIDIOC_INT_I2S_CLOCK_FREQ)] = "VIDIOC_INT_I2S_CLOCK_FREQ", |
415 | [_IOC_NR(VIDIOC_INT_S_STANDBY)] = "VIDIOC_INT_S_STANDBY", | 420 | [_IOC_NR(VIDIOC_INT_S_STANDBY)] = "VIDIOC_INT_S_STANDBY", |
416 | [_IOC_NR(VIDIOC_INT_S_AUDIO_ROUTING)] = "VIDIOC_INT_S_AUDIO_ROUTING", | 421 | [_IOC_NR(VIDIOC_INT_S_AUDIO_ROUTING)] = "VIDIOC_INT_S_AUDIO_ROUTING", |
417 | [_IOC_NR(VIDIOC_INT_G_AUDIO_ROUTING)] = "VIDIOC_INT_G_AUDIO_ROUTING", | 422 | [_IOC_NR(VIDIOC_INT_G_AUDIO_ROUTING)] = "VIDIOC_INT_G_AUDIO_ROUTING", |
418 | [_IOC_NR(VIDIOC_INT_S_VIDEO_ROUTING)] = "VIDIOC_INT_S_VIDEO_ROUTING", | 423 | [_IOC_NR(VIDIOC_INT_S_VIDEO_ROUTING)] = "VIDIOC_INT_S_VIDEO_ROUTING", |
419 | [_IOC_NR(VIDIOC_INT_G_VIDEO_ROUTING)] = "VIDIOC_INT_G_VIDEO_ROUTING", | 424 | [_IOC_NR(VIDIOC_INT_G_VIDEO_ROUTING)] = "VIDIOC_INT_G_VIDEO_ROUTING", |
420 | [_IOC_NR(VIDIOC_INT_S_CRYSTAL_FREQ)] = "VIDIOC_INT_S_CRYSTAL_FREQ" | 425 | [_IOC_NR(VIDIOC_INT_S_CRYSTAL_FREQ)] = "VIDIOC_INT_S_CRYSTAL_FREQ", |
426 | [_IOC_NR(VIDIOC_INT_INIT)] = "VIDIOC_INT_INIT", | ||
427 | [_IOC_NR(VIDIOC_INT_G_STD_OUTPUT)] = "VIDIOC_INT_G_STD_OUTPUT", | ||
428 | [_IOC_NR(VIDIOC_INT_S_STD_OUTPUT)] = "VIDIOC_INT_S_STD_OUTPUT", | ||
421 | }; | 429 | }; |
422 | #define V4L2_INT_IOCTLS ARRAY_SIZE(v4l2_int_ioctls) | 430 | #define V4L2_INT_IOCTLS ARRAY_SIZE(v4l2_int_ioctls) |
423 | 431 | ||
@@ -680,6 +688,7 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste | |||
680 | case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: name = "Audio Stereo Mode Extension"; break; | 688 | case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: name = "Audio Stereo Mode Extension"; break; |
681 | case V4L2_CID_MPEG_AUDIO_EMPHASIS: name = "Audio Emphasis"; break; | 689 | case V4L2_CID_MPEG_AUDIO_EMPHASIS: name = "Audio Emphasis"; break; |
682 | case V4L2_CID_MPEG_AUDIO_CRC: name = "Audio CRC"; break; | 690 | case V4L2_CID_MPEG_AUDIO_CRC: name = "Audio CRC"; break; |
691 | case V4L2_CID_MPEG_AUDIO_MUTE: name = "Audio Mute"; break; | ||
683 | case V4L2_CID_MPEG_VIDEO_ENCODING: name = "Video Encoding"; break; | 692 | case V4L2_CID_MPEG_VIDEO_ENCODING: name = "Video Encoding"; break; |
684 | case V4L2_CID_MPEG_VIDEO_ASPECT: name = "Video Aspect"; break; | 693 | case V4L2_CID_MPEG_VIDEO_ASPECT: name = "Video Aspect"; break; |
685 | case V4L2_CID_MPEG_VIDEO_B_FRAMES: name = "Video B Frames"; break; | 694 | case V4L2_CID_MPEG_VIDEO_B_FRAMES: name = "Video B Frames"; break; |
@@ -690,6 +699,8 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste | |||
690 | case V4L2_CID_MPEG_VIDEO_BITRATE: name = "Video Bitrate"; break; | 699 | case V4L2_CID_MPEG_VIDEO_BITRATE: name = "Video Bitrate"; break; |
691 | case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: name = "Video Peak Bitrate"; break; | 700 | case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: name = "Video Peak Bitrate"; break; |
692 | case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: name = "Video Temporal Decimation"; break; | 701 | case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: name = "Video Temporal Decimation"; break; |
702 | case V4L2_CID_MPEG_VIDEO_MUTE: name = "Video Mute"; break; | ||
703 | case V4L2_CID_MPEG_VIDEO_MUTE_YUV: name = "Video Mute YUV"; break; | ||
693 | case V4L2_CID_MPEG_STREAM_TYPE: name = "Stream Type"; break; | 704 | case V4L2_CID_MPEG_STREAM_TYPE: name = "Stream Type"; break; |
694 | case V4L2_CID_MPEG_STREAM_PID_PMT: name = "Stream PMT Program ID"; break; | 705 | case V4L2_CID_MPEG_STREAM_PID_PMT: name = "Stream PMT Program ID"; break; |
695 | case V4L2_CID_MPEG_STREAM_PID_AUDIO: name = "Stream Audio Program ID"; break; | 706 | case V4L2_CID_MPEG_STREAM_PID_AUDIO: name = "Stream Audio Program ID"; break; |
@@ -705,6 +716,7 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste | |||
705 | switch (qctrl->id) { | 716 | switch (qctrl->id) { |
706 | case V4L2_CID_AUDIO_MUTE: | 717 | case V4L2_CID_AUDIO_MUTE: |
707 | case V4L2_CID_AUDIO_LOUDNESS: | 718 | case V4L2_CID_AUDIO_LOUDNESS: |
719 | case V4L2_CID_MPEG_AUDIO_MUTE: | ||
708 | case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: | 720 | case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: |
709 | case V4L2_CID_MPEG_VIDEO_PULLDOWN: | 721 | case V4L2_CID_MPEG_VIDEO_PULLDOWN: |
710 | qctrl->type = V4L2_CTRL_TYPE_BOOLEAN; | 722 | qctrl->type = V4L2_CTRL_TYPE_BOOLEAN; |
@@ -838,6 +850,8 @@ int v4l2_ctrl_query_fill_std(struct v4l2_queryctrl *qctrl) | |||
838 | V4L2_MPEG_AUDIO_CRC_NONE, | 850 | V4L2_MPEG_AUDIO_CRC_NONE, |
839 | V4L2_MPEG_AUDIO_CRC_CRC16, 1, | 851 | V4L2_MPEG_AUDIO_CRC_CRC16, 1, |
840 | V4L2_MPEG_AUDIO_CRC_NONE); | 852 | V4L2_MPEG_AUDIO_CRC_NONE); |
853 | case V4L2_CID_MPEG_AUDIO_MUTE: | ||
854 | return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 0); | ||
841 | case V4L2_CID_MPEG_VIDEO_ENCODING: | 855 | case V4L2_CID_MPEG_VIDEO_ENCODING: |
842 | return v4l2_ctrl_query_fill(qctrl, | 856 | return v4l2_ctrl_query_fill(qctrl, |
843 | V4L2_MPEG_VIDEO_ENCODING_MPEG_1, | 857 | V4L2_MPEG_VIDEO_ENCODING_MPEG_1, |
@@ -867,6 +881,10 @@ int v4l2_ctrl_query_fill_std(struct v4l2_queryctrl *qctrl) | |||
867 | return v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 8000000); | 881 | return v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 8000000); |
868 | case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: | 882 | case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: |
869 | return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 0); | 883 | return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 0); |
884 | case V4L2_CID_MPEG_VIDEO_MUTE: | ||
885 | return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 0); | ||
886 | case V4L2_CID_MPEG_VIDEO_MUTE_YUV: /* Init YUV (really YCbCr) to black */ | ||
887 | return v4l2_ctrl_query_fill(qctrl, 0, 0xffffff, 1, 0x008080); | ||
870 | case V4L2_CID_MPEG_STREAM_TYPE: | 888 | case V4L2_CID_MPEG_STREAM_TYPE: |
871 | return v4l2_ctrl_query_fill(qctrl, | 889 | return v4l2_ctrl_query_fill(qctrl, |
872 | V4L2_MPEG_STREAM_TYPE_MPEG2_PS, | 890 | V4L2_MPEG_STREAM_TYPE_MPEG2_PS, |
@@ -965,6 +983,22 @@ int v4l2_chip_match_i2c_client(struct i2c_client *c, u32 match_type, u32 match_c | |||
965 | } | 983 | } |
966 | } | 984 | } |
967 | 985 | ||
986 | int v4l2_chip_ident_i2c_client(struct i2c_client *c, struct v4l2_chip_ident *chip, | ||
987 | u32 ident, u32 revision) | ||
988 | { | ||
989 | if (!v4l2_chip_match_i2c_client(c, chip->match_type, chip->match_chip)) | ||
990 | return 0; | ||
991 | if (chip->ident == V4L2_IDENT_NONE) { | ||
992 | chip->ident = ident; | ||
993 | chip->revision = revision; | ||
994 | } | ||
995 | else { | ||
996 | chip->ident = V4L2_IDENT_AMBIGUOUS; | ||
997 | chip->revision = 0; | ||
998 | } | ||
999 | return 0; | ||
1000 | } | ||
1001 | |||
968 | int v4l2_chip_match_host(u32 match_type, u32 match_chip) | 1002 | int v4l2_chip_match_host(u32 match_type, u32 match_chip) |
969 | { | 1003 | { |
970 | switch (match_type) { | 1004 | switch (match_type) { |
@@ -999,6 +1033,7 @@ EXPORT_SYMBOL(v4l2_ctrl_query_fill); | |||
999 | EXPORT_SYMBOL(v4l2_ctrl_query_fill_std); | 1033 | EXPORT_SYMBOL(v4l2_ctrl_query_fill_std); |
1000 | 1034 | ||
1001 | EXPORT_SYMBOL(v4l2_chip_match_i2c_client); | 1035 | EXPORT_SYMBOL(v4l2_chip_match_i2c_client); |
1036 | EXPORT_SYMBOL(v4l2_chip_ident_i2c_client); | ||
1002 | EXPORT_SYMBOL(v4l2_chip_match_host); | 1037 | EXPORT_SYMBOL(v4l2_chip_match_host); |
1003 | 1038 | ||
1004 | /* | 1039 | /* |
diff --git a/drivers/media/video/videocodec.c b/drivers/media/video/videocodec.c index 290e64135650..f2bbd7a4d562 100644 --- a/drivers/media/video/videocodec.c +++ b/drivers/media/video/videocodec.c | |||
@@ -348,6 +348,9 @@ videocodec_build_table (void) | |||
348 | kfree(videocodec_buf); | 348 | kfree(videocodec_buf); |
349 | videocodec_buf = kmalloc(size, GFP_KERNEL); | 349 | videocodec_buf = kmalloc(size, GFP_KERNEL); |
350 | 350 | ||
351 | if (!videocodec_buf) | ||
352 | return 0; | ||
353 | |||
351 | i = 0; | 354 | i = 0; |
352 | i += scnprintf(videocodec_buf + i, size - 1, | 355 | i += scnprintf(videocodec_buf + i, size - 1, |
353 | "<S>lave or attached <M>aster name type flags magic "); | 356 | "<S>lave or attached <M>aster name type flags magic "); |
diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c index 011938fb7e0e..80ac5f86d9e5 100644 --- a/drivers/media/video/videodev.c +++ b/drivers/media/video/videodev.c | |||
@@ -318,6 +318,7 @@ static char *v4l2_type_names_FIXME[] = { | |||
318 | [V4L2_BUF_TYPE_VBI_OUTPUT] = "vbi-out", | 318 | [V4L2_BUF_TYPE_VBI_OUTPUT] = "vbi-out", |
319 | [V4L2_BUF_TYPE_SLICED_VBI_OUTPUT] = "sliced-vbi-out", | 319 | [V4L2_BUF_TYPE_SLICED_VBI_OUTPUT] = "sliced-vbi-out", |
320 | [V4L2_BUF_TYPE_SLICED_VBI_CAPTURE] = "sliced-vbi-capture", | 320 | [V4L2_BUF_TYPE_SLICED_VBI_CAPTURE] = "sliced-vbi-capture", |
321 | [V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY] = "video-out-over", | ||
321 | [V4L2_BUF_TYPE_PRIVATE] = "private", | 322 | [V4L2_BUF_TYPE_PRIVATE] = "private", |
322 | }; | 323 | }; |
323 | 324 | ||
@@ -330,6 +331,8 @@ static char *v4l2_field_names_FIXME[] = { | |||
330 | [V4L2_FIELD_SEQ_TB] = "seq-tb", | 331 | [V4L2_FIELD_SEQ_TB] = "seq-tb", |
331 | [V4L2_FIELD_SEQ_BT] = "seq-bt", | 332 | [V4L2_FIELD_SEQ_BT] = "seq-bt", |
332 | [V4L2_FIELD_ALTERNATE] = "alternate", | 333 | [V4L2_FIELD_ALTERNATE] = "alternate", |
334 | [V4L2_FIELD_INTERLACED_TB] = "interlaced-tb", | ||
335 | [V4L2_FIELD_INTERLACED_BT] = "interlaced-bt", | ||
333 | }; | 336 | }; |
334 | 337 | ||
335 | #define prt_names(a,arr) (((a)>=0)&&((a)<ARRAY_SIZE(arr)))?arr[a]:"unknown" | 338 | #define prt_names(a,arr) (((a)>=0)&&((a)<ARRAY_SIZE(arr)))?arr[a]:"unknown" |
@@ -411,6 +414,10 @@ static int check_fmt (struct video_device *vfd, enum v4l2_buf_type type) | |||
411 | if (vfd->vidioc_try_fmt_vbi_output) | 414 | if (vfd->vidioc_try_fmt_vbi_output) |
412 | return (0); | 415 | return (0); |
413 | break; | 416 | break; |
417 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: | ||
418 | if (vfd->vidioc_try_fmt_output_overlay) | ||
419 | return (0); | ||
420 | break; | ||
414 | case V4L2_BUF_TYPE_PRIVATE: | 421 | case V4L2_BUF_TYPE_PRIVATE: |
415 | if (vfd->vidioc_try_fmt_type_private) | 422 | if (vfd->vidioc_try_fmt_type_private) |
416 | return (0); | 423 | return (0); |
@@ -525,6 +532,10 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, | |||
525 | ret=vfd->vidioc_enum_fmt_vbi_output(file, | 532 | ret=vfd->vidioc_enum_fmt_vbi_output(file, |
526 | fh, f); | 533 | fh, f); |
527 | break; | 534 | break; |
535 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: | ||
536 | if (vfd->vidioc_enum_fmt_output_overlay) | ||
537 | ret=vfd->vidioc_enum_fmt_output_overlay(file, fh, f); | ||
538 | break; | ||
528 | case V4L2_BUF_TYPE_PRIVATE: | 539 | case V4L2_BUF_TYPE_PRIVATE: |
529 | if (vfd->vidioc_enum_fmt_type_private) | 540 | if (vfd->vidioc_enum_fmt_type_private) |
530 | ret=vfd->vidioc_enum_fmt_type_private(file, | 541 | ret=vfd->vidioc_enum_fmt_type_private(file, |
@@ -582,6 +593,10 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, | |||
582 | ret=vfd->vidioc_g_fmt_video_output(file, | 593 | ret=vfd->vidioc_g_fmt_video_output(file, |
583 | fh, f); | 594 | fh, f); |
584 | break; | 595 | break; |
596 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: | ||
597 | if (vfd->vidioc_g_fmt_output_overlay) | ||
598 | ret=vfd->vidioc_g_fmt_output_overlay(file, fh, f); | ||
599 | break; | ||
585 | case V4L2_BUF_TYPE_VBI_OUTPUT: | 600 | case V4L2_BUF_TYPE_VBI_OUTPUT: |
586 | if (vfd->vidioc_g_fmt_vbi_output) | 601 | if (vfd->vidioc_g_fmt_vbi_output) |
587 | ret=vfd->vidioc_g_fmt_vbi_output(file, fh, f); | 602 | ret=vfd->vidioc_g_fmt_vbi_output(file, fh, f); |
@@ -630,6 +645,10 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, | |||
630 | ret=vfd->vidioc_s_fmt_video_output(file, | 645 | ret=vfd->vidioc_s_fmt_video_output(file, |
631 | fh, f); | 646 | fh, f); |
632 | break; | 647 | break; |
648 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: | ||
649 | if (vfd->vidioc_s_fmt_output_overlay) | ||
650 | ret=vfd->vidioc_s_fmt_output_overlay(file, fh, f); | ||
651 | break; | ||
633 | case V4L2_BUF_TYPE_VBI_OUTPUT: | 652 | case V4L2_BUF_TYPE_VBI_OUTPUT: |
634 | if (vfd->vidioc_s_fmt_vbi_output) | 653 | if (vfd->vidioc_s_fmt_vbi_output) |
635 | ret=vfd->vidioc_s_fmt_vbi_output(file, | 654 | ret=vfd->vidioc_s_fmt_vbi_output(file, |
@@ -680,6 +699,10 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, | |||
680 | ret=vfd->vidioc_try_fmt_video_output(file, | 699 | ret=vfd->vidioc_try_fmt_video_output(file, |
681 | fh, f); | 700 | fh, f); |
682 | break; | 701 | break; |
702 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: | ||
703 | if (vfd->vidioc_try_fmt_output_overlay) | ||
704 | ret=vfd->vidioc_try_fmt_output_overlay(file, fh, f); | ||
705 | break; | ||
683 | case V4L2_BUF_TYPE_VBI_OUTPUT: | 706 | case V4L2_BUF_TYPE_VBI_OUTPUT: |
684 | if (vfd->vidioc_try_fmt_vbi_output) | 707 | if (vfd->vidioc_try_fmt_vbi_output) |
685 | ret=vfd->vidioc_try_fmt_vbi_output(file, | 708 | ret=vfd->vidioc_try_fmt_vbi_output(file, |
@@ -1381,6 +1404,11 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, | |||
1381 | case VIDIOC_G_PARM: | 1404 | case VIDIOC_G_PARM: |
1382 | { | 1405 | { |
1383 | struct v4l2_streamparm *p=arg; | 1406 | struct v4l2_streamparm *p=arg; |
1407 | __u32 type=p->type; | ||
1408 | |||
1409 | memset(p,0,sizeof(*p)); | ||
1410 | p->type=type; | ||
1411 | |||
1384 | if (vfd->vidioc_g_parm) { | 1412 | if (vfd->vidioc_g_parm) { |
1385 | ret=vfd->vidioc_g_parm(file, fh, p); | 1413 | ret=vfd->vidioc_g_parm(file, fh, p); |
1386 | } else { | 1414 | } else { |
@@ -1392,8 +1420,6 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, | |||
1392 | v4l2_video_std_construct(&s, vfd->current_norm, | 1420 | v4l2_video_std_construct(&s, vfd->current_norm, |
1393 | v4l2_norm_to_name(vfd->current_norm)); | 1421 | v4l2_norm_to_name(vfd->current_norm)); |
1394 | 1422 | ||
1395 | memset(p,0,sizeof(*p)); | ||
1396 | |||
1397 | p->parm.capture.timeperframe = s.frameperiod; | 1423 | p->parm.capture.timeperframe = s.frameperiod; |
1398 | ret=0; | 1424 | ret=0; |
1399 | } | 1425 | } |
@@ -1509,6 +1535,16 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, | |||
1509 | break; | 1535 | break; |
1510 | } | 1536 | } |
1511 | #endif | 1537 | #endif |
1538 | case VIDIOC_G_CHIP_IDENT: | ||
1539 | { | ||
1540 | struct v4l2_chip_ident *p=arg; | ||
1541 | if (!vfd->vidioc_g_chip_ident) | ||
1542 | break; | ||
1543 | ret=vfd->vidioc_g_chip_ident(file, fh, p); | ||
1544 | if (!ret) | ||
1545 | dbgarg (cmd, "chip_ident=%u, revision=0x%x\n", p->ident, p->revision); | ||
1546 | break; | ||
1547 | } | ||
1512 | } /* switch */ | 1548 | } /* switch */ |
1513 | 1549 | ||
1514 | if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) { | 1550 | if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) { |
diff --git a/drivers/media/video/wm8739.c b/drivers/media/video/wm8739.c index a9b59c35cd67..8f6741a28a47 100644 --- a/drivers/media/video/wm8739.c +++ b/drivers/media/video/wm8739.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/i2c-id.h> | 29 | #include <linux/i2c-id.h> |
30 | #include <linux/videodev.h> | 30 | #include <linux/videodev.h> |
31 | #include <media/v4l2-common.h> | 31 | #include <media/v4l2-common.h> |
32 | #include <media/v4l2-chip-ident.h> | ||
32 | 33 | ||
33 | MODULE_DESCRIPTION("wm8739 driver"); | 34 | MODULE_DESCRIPTION("wm8739 driver"); |
34 | MODULE_AUTHOR("T. Adachi, Hans Verkuil"); | 35 | MODULE_AUTHOR("T. Adachi, Hans Verkuil"); |
@@ -236,6 +237,9 @@ static int wm8739_command(struct i2c_client *client, unsigned int cmd, void *arg | |||
236 | return -EINVAL; | 237 | return -EINVAL; |
237 | } | 238 | } |
238 | 239 | ||
240 | case VIDIOC_G_CHIP_IDENT: | ||
241 | return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_WM8739, 0); | ||
242 | |||
239 | case VIDIOC_LOG_STATUS: | 243 | case VIDIOC_LOG_STATUS: |
240 | v4l_info(client, "Frequency: %u Hz\n", state->clock_freq); | 244 | v4l_info(client, "Frequency: %u Hz\n", state->clock_freq); |
241 | v4l_info(client, "Volume L: %02x%s\n", state->vol_l & 0x1f, | 245 | v4l_info(client, "Volume L: %02x%s\n", state->vol_l & 0x1f, |
diff --git a/drivers/media/video/wm8775.c b/drivers/media/video/wm8775.c index d81a88bbe43d..4df5d30d4d09 100644 --- a/drivers/media/video/wm8775.c +++ b/drivers/media/video/wm8775.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/i2c-id.h> | 33 | #include <linux/i2c-id.h> |
34 | #include <linux/videodev.h> | 34 | #include <linux/videodev.h> |
35 | #include <media/v4l2-common.h> | 35 | #include <media/v4l2-common.h> |
36 | #include <media/v4l2-chip-ident.h> | ||
36 | 37 | ||
37 | MODULE_DESCRIPTION("wm8775 driver"); | 38 | MODULE_DESCRIPTION("wm8775 driver"); |
38 | MODULE_AUTHOR("Ulf Eklund, Hans Verkuil"); | 39 | MODULE_AUTHOR("Ulf Eklund, Hans Verkuil"); |
@@ -124,6 +125,9 @@ static int wm8775_command(struct i2c_client *client, unsigned int cmd, | |||
124 | wm8775_write(client, R21, 0x100 + state->input); | 125 | wm8775_write(client, R21, 0x100 + state->input); |
125 | break; | 126 | break; |
126 | 127 | ||
128 | case VIDIOC_G_CHIP_IDENT: | ||
129 | return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_WM8775, 0); | ||
130 | |||
127 | case VIDIOC_LOG_STATUS: | 131 | case VIDIOC_LOG_STATUS: |
128 | v4l_info(client, "Input: %d%s\n", state->input, | 132 | v4l_info(client, "Input: %d%s\n", state->input, |
129 | state->muted ? " (muted)" : ""); | 133 | state->muted ? " (muted)" : ""); |
diff --git a/drivers/media/video/zr364xx.c b/drivers/media/video/zr364xx.c new file mode 100644 index 000000000000..b5d3364c94c7 --- /dev/null +++ b/drivers/media/video/zr364xx.c | |||
@@ -0,0 +1,929 @@ | |||
1 | /* | ||
2 | * Zoran 364xx based USB webcam module version 0.72 | ||
3 | * | ||
4 | * Allows you to use your USB webcam with V4L2 applications | ||
5 | * This is still in heavy developpement ! | ||
6 | * | ||
7 | * Copyright (C) 2004 Antoine Jacquet <royale@zerezo.com> | ||
8 | * http://royale.zerezo.com/zr364xx/ | ||
9 | * | ||
10 | * Heavily inspired by usb-skeleton.c, vicam.c, cpia.c and spca50x.c drivers | ||
11 | * V4L2 version inspired by meye.c driver | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License as published by | ||
15 | * the Free Software Foundation; either version 2 of the License, or | ||
16 | * (at your option) any later version. | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, | ||
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
21 | * GNU General Public License for more details. | ||
22 | * | ||
23 | * You should have received a copy of the GNU General Public License | ||
24 | * along with this program; if not, write to the Free Software | ||
25 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
26 | */ | ||
27 | |||
28 | |||
29 | #include <linux/version.h> | ||
30 | #include <linux/module.h> | ||
31 | #include <linux/init.h> | ||
32 | #include <linux/usb.h> | ||
33 | #include <linux/vmalloc.h> | ||
34 | #include <linux/slab.h> | ||
35 | #include <linux/proc_fs.h> | ||
36 | #include <linux/highmem.h> | ||
37 | #include <media/v4l2-common.h> | ||
38 | |||
39 | |||
40 | /* Version Information */ | ||
41 | #define DRIVER_VERSION "v0.72" | ||
42 | #define DRIVER_AUTHOR "Antoine Jacquet, http://royale.zerezo.com/" | ||
43 | #define DRIVER_DESC "Zoran 364xx" | ||
44 | |||
45 | |||
46 | /* Camera */ | ||
47 | #define FRAMES 2 | ||
48 | #define MAX_FRAME_SIZE 100000 | ||
49 | #define BUFFER_SIZE 0x1000 | ||
50 | #define CTRL_TIMEOUT 500 | ||
51 | |||
52 | |||
53 | /* Debug macro */ | ||
54 | #define DBG(x...) if (debug) info(x) | ||
55 | |||
56 | |||
57 | /* Init methods, need to find nicer names for these | ||
58 | * the exact names of the chipsets would be the best if someone finds it */ | ||
59 | #define METHOD0 0 | ||
60 | #define METHOD1 1 | ||
61 | #define METHOD2 2 | ||
62 | |||
63 | |||
64 | /* Module parameters */ | ||
65 | static int debug = 0; | ||
66 | static int mode = 0; | ||
67 | |||
68 | |||
69 | /* Module parameters interface */ | ||
70 | module_param(debug, int, 0644); | ||
71 | MODULE_PARM_DESC(debug, "Debug level"); | ||
72 | module_param(mode, int, 0644); | ||
73 | MODULE_PARM_DESC(mode, "0 = 320x240, 1 = 160x120, 2 = 640x480"); | ||
74 | |||
75 | |||
76 | /* Devices supported by this driver | ||
77 | * .driver_info contains the init method used by the camera */ | ||
78 | static struct usb_device_id device_table[] = { | ||
79 | {USB_DEVICE(0x08ca, 0x0109), .driver_info = METHOD0 }, | ||
80 | {USB_DEVICE(0x041e, 0x4024), .driver_info = METHOD0 }, | ||
81 | {USB_DEVICE(0x0d64, 0x0108), .driver_info = METHOD0 }, | ||
82 | {USB_DEVICE(0x0546, 0x3187), .driver_info = METHOD0 }, | ||
83 | {USB_DEVICE(0x0d64, 0x3108), .driver_info = METHOD0 }, | ||
84 | {USB_DEVICE(0x0595, 0x4343), .driver_info = METHOD0 }, | ||
85 | {USB_DEVICE(0x0bb0, 0x500d), .driver_info = METHOD0 }, | ||
86 | {USB_DEVICE(0x0feb, 0x2004), .driver_info = METHOD0 }, | ||
87 | {USB_DEVICE(0x055f, 0xb500), .driver_info = METHOD0 }, | ||
88 | {USB_DEVICE(0x08ca, 0x2062), .driver_info = METHOD2 }, | ||
89 | {USB_DEVICE(0x052b, 0x1a18), .driver_info = METHOD1 }, | ||
90 | {USB_DEVICE(0x04c8, 0x0729), .driver_info = METHOD0 }, | ||
91 | {USB_DEVICE(0x04f2, 0xa208), .driver_info = METHOD0 }, | ||
92 | {USB_DEVICE(0x0784, 0x0040), .driver_info = METHOD1 }, | ||
93 | {USB_DEVICE(0x06d6, 0x0034), .driver_info = METHOD0 }, | ||
94 | {USB_DEVICE(0x0a17, 0x0062), .driver_info = METHOD2 }, | ||
95 | {} /* Terminating entry */ | ||
96 | }; | ||
97 | |||
98 | MODULE_DEVICE_TABLE(usb, device_table); | ||
99 | |||
100 | |||
101 | /* Camera stuff */ | ||
102 | struct zr364xx_camera { | ||
103 | struct usb_device *udev; /* save off the usb device pointer */ | ||
104 | struct usb_interface *interface;/* the interface for this device */ | ||
105 | struct video_device *vdev; /* v4l video device */ | ||
106 | u8 *framebuf; | ||
107 | int nb; | ||
108 | unsigned char *buffer; | ||
109 | int skip; | ||
110 | int brightness; | ||
111 | int width; | ||
112 | int height; | ||
113 | int method; | ||
114 | struct mutex lock; | ||
115 | }; | ||
116 | |||
117 | |||
118 | /* function used to send initialisation commands to the camera */ | ||
119 | static int send_control_msg(struct usb_device *udev, u8 request, u16 value, | ||
120 | u16 index, unsigned char *cp, u16 size) | ||
121 | { | ||
122 | int status; | ||
123 | |||
124 | unsigned char *transfer_buffer = kmalloc(size, GFP_KERNEL); | ||
125 | if (!transfer_buffer) { | ||
126 | info("kmalloc(%d) failed", size); | ||
127 | return -ENOMEM; | ||
128 | } | ||
129 | |||
130 | memcpy(transfer_buffer, cp, size); | ||
131 | |||
132 | status = usb_control_msg(udev, | ||
133 | usb_sndctrlpipe(udev, 0), | ||
134 | request, | ||
135 | USB_DIR_OUT | USB_TYPE_VENDOR | | ||
136 | USB_RECIP_DEVICE, value, index, | ||
137 | transfer_buffer, size, CTRL_TIMEOUT); | ||
138 | |||
139 | kfree(transfer_buffer); | ||
140 | |||
141 | if (status < 0) | ||
142 | info("Failed sending control message, error %d.", status); | ||
143 | |||
144 | return status; | ||
145 | } | ||
146 | |||
147 | |||
148 | /* Control messages sent to the camera to initialize it | ||
149 | * and launch the capture */ | ||
150 | typedef struct { | ||
151 | unsigned int value; | ||
152 | unsigned int size; | ||
153 | unsigned char *bytes; | ||
154 | } message; | ||
155 | |||
156 | /* method 0 */ | ||
157 | static unsigned char m0d1[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; | ||
158 | static unsigned char m0d2[] = { 0, 0, 0, 0, 0, 0 }; | ||
159 | static unsigned char m0d3[] = { 0, 0 }; | ||
160 | static message m0[] = { | ||
161 | {0x1f30, 0, NULL}, | ||
162 | {0xd000, 0, NULL}, | ||
163 | {0x3370, sizeof(m0d1), m0d1}, | ||
164 | {0x2000, 0, NULL}, | ||
165 | {0x2f0f, 0, NULL}, | ||
166 | {0x2610, sizeof(m0d2), m0d2}, | ||
167 | {0xe107, 0, NULL}, | ||
168 | {0x2502, 0, NULL}, | ||
169 | {0x1f70, 0, NULL}, | ||
170 | {0xd000, 0, NULL}, | ||
171 | {0x9a01, sizeof(m0d3), m0d3}, | ||
172 | {-1, -1, NULL} | ||
173 | }; | ||
174 | |||
175 | /* method 1 */ | ||
176 | static unsigned char m1d1[] = { 0xff, 0xff }; | ||
177 | static unsigned char m1d2[] = { 0x00, 0x00 }; | ||
178 | static message m1[] = { | ||
179 | {0x1f30, 0, NULL}, | ||
180 | {0xd000, 0, NULL}, | ||
181 | {0xf000, 0, NULL}, | ||
182 | {0x2000, 0, NULL}, | ||
183 | {0x2f0f, 0, NULL}, | ||
184 | {0x2650, 0, NULL}, | ||
185 | {0xe107, 0, NULL}, | ||
186 | {0x2502, sizeof(m1d1), m1d1}, | ||
187 | {0x1f70, 0, NULL}, | ||
188 | {0xd000, 0, NULL}, | ||
189 | {0xd000, 0, NULL}, | ||
190 | {0xd000, 0, NULL}, | ||
191 | {0x9a01, sizeof(m1d2), m1d2}, | ||
192 | {-1, -1, NULL} | ||
193 | }; | ||
194 | |||
195 | /* method 2 */ | ||
196 | static unsigned char m2d1[] = { 0xff, 0xff }; | ||
197 | static message m2[] = { | ||
198 | {0x1f30, 0, NULL}, | ||
199 | {0xf000, 0, NULL}, | ||
200 | {0x2000, 0, NULL}, | ||
201 | {0x2f0f, 0, NULL}, | ||
202 | {0x2650, 0, NULL}, | ||
203 | {0xe107, 0, NULL}, | ||
204 | {0x2502, sizeof(m2d1), m2d1}, | ||
205 | {0x1f70, 0, NULL}, | ||
206 | {-1, -1, NULL} | ||
207 | }; | ||
208 | |||
209 | /* init table */ | ||
210 | static message *init[3] = { m0, m1, m2 }; | ||
211 | |||
212 | |||
213 | /* JPEG static data in header (Huffman table, etc) */ | ||
214 | static unsigned char header1[] = { | ||
215 | 0xFF, 0xD8, | ||
216 | /* | ||
217 | 0xFF, 0xE0, 0x00, 0x10, 'J', 'F', 'I', 'F', | ||
218 | 0x00, 0x01, 0x01, 0x00, 0x33, 0x8A, 0x00, 0x00, 0x33, 0x88, | ||
219 | */ | ||
220 | 0xFF, 0xDB, 0x00, 0x84 | ||
221 | }; | ||
222 | static unsigned char header2[] = { | ||
223 | 0xFF, 0xC4, 0x00, 0x1F, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, | ||
224 | 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
225 | 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, | ||
226 | 0xFF, 0xC4, 0x00, 0xB5, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, | ||
227 | 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7D, 0x01, | ||
228 | 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, | ||
229 | 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xA1, | ||
230 | 0x08, 0x23, 0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0, 0x24, 0x33, | ||
231 | 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x25, | ||
232 | 0x26, 0x27, 0x28, 0x29, 0x2A, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, | ||
233 | 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, | ||
234 | 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, | ||
235 | 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, | ||
236 | 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, | ||
237 | 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, | ||
238 | 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, | ||
239 | 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, | ||
240 | 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE1, 0xE2, | ||
241 | 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF1, 0xF2, 0xF3, | ||
242 | 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFF, 0xC4, 0x00, 0x1F, | ||
243 | 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, | ||
244 | 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, | ||
245 | 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0xFF, 0xC4, 0x00, 0xB5, | ||
246 | 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, | ||
247 | 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, | ||
248 | 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, | ||
249 | 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xA1, 0xB1, 0xC1, | ||
250 | 0x09, 0x23, 0x33, 0x52, 0xF0, 0x15, 0x62, 0x72, 0xD1, 0x0A, 0x16, | ||
251 | 0x24, 0x34, 0xE1, 0x25, 0xF1, 0x17, 0x18, 0x19, 0x1A, 0x26, 0x27, | ||
252 | 0x28, 0x29, 0x2A, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, | ||
253 | 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, | ||
254 | 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, | ||
255 | 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x82, 0x83, 0x84, | ||
256 | 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, | ||
257 | 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, | ||
258 | 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, | ||
259 | 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, | ||
260 | 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE2, 0xE3, 0xE4, 0xE5, | ||
261 | 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, | ||
262 | 0xF8, 0xF9, 0xFA, 0xFF, 0xC0, 0x00, 0x11, 0x08, 0x00, 0xF0, 0x01, | ||
263 | 0x40, 0x03, 0x01, 0x21, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, | ||
264 | 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, | ||
265 | 0x00, 0x3F, 0x00 | ||
266 | }; | ||
267 | static unsigned char header3; | ||
268 | |||
269 | |||
270 | |||
271 | /********************/ | ||
272 | /* V4L2 integration */ | ||
273 | /********************/ | ||
274 | |||
275 | /* this function reads a full JPEG picture synchronously | ||
276 | * TODO: do it asynchronously... */ | ||
277 | static int read_frame(struct zr364xx_camera *cam, int framenum) | ||
278 | { | ||
279 | int i, n, temp, head, size, actual_length; | ||
280 | unsigned char *ptr = NULL, *jpeg; | ||
281 | |||
282 | redo: | ||
283 | /* hardware brightness */ | ||
284 | n = send_control_msg(cam->udev, 1, 0x2001, 0, NULL, 0); | ||
285 | temp = (0x60 << 8) + 127 - cam->brightness; | ||
286 | n = send_control_msg(cam->udev, 1, temp, 0, NULL, 0); | ||
287 | |||
288 | /* during the first loop we are going to insert JPEG header */ | ||
289 | head = 0; | ||
290 | /* this is the place in memory where we are going to build | ||
291 | * the JPEG image */ | ||
292 | jpeg = cam->framebuf + framenum * MAX_FRAME_SIZE; | ||
293 | /* read data... */ | ||
294 | do { | ||
295 | n = usb_bulk_msg(cam->udev, | ||
296 | usb_rcvbulkpipe(cam->udev, 0x81), | ||
297 | cam->buffer, BUFFER_SIZE, &actual_length, | ||
298 | CTRL_TIMEOUT); | ||
299 | DBG("buffer : %d %d", cam->buffer[0], cam->buffer[1]); | ||
300 | DBG("bulk : n=%d size=%d", n, actual_length); | ||
301 | if (n < 0) { | ||
302 | info("error reading bulk msg"); | ||
303 | return 0; | ||
304 | } | ||
305 | if (actual_length < 0 || actual_length > BUFFER_SIZE) { | ||
306 | info("wrong number of bytes"); | ||
307 | return 0; | ||
308 | } | ||
309 | |||
310 | /* swap bytes if camera needs it */ | ||
311 | if (cam->method == METHOD0) { | ||
312 | u16 *buf = (u16*)cam->buffer; | ||
313 | for (i = 0; i < BUFFER_SIZE/2; i++) | ||
314 | swab16s(buf + i); | ||
315 | } | ||
316 | |||
317 | /* write the JPEG header */ | ||
318 | if (!head) { | ||
319 | DBG("jpeg header"); | ||
320 | ptr = jpeg; | ||
321 | memcpy(ptr, header1, sizeof(header1)); | ||
322 | ptr += sizeof(header1); | ||
323 | header3 = 0; | ||
324 | memcpy(ptr, &header3, 1); | ||
325 | ptr++; | ||
326 | memcpy(ptr, cam->buffer, 64); | ||
327 | ptr += 64; | ||
328 | header3 = 1; | ||
329 | memcpy(ptr, &header3, 1); | ||
330 | ptr++; | ||
331 | memcpy(ptr, cam->buffer + 64, 64); | ||
332 | ptr += 64; | ||
333 | memcpy(ptr, header2, sizeof(header2)); | ||
334 | ptr += sizeof(header2); | ||
335 | memcpy(ptr, cam->buffer + 128, | ||
336 | actual_length - 128); | ||
337 | ptr += actual_length - 128; | ||
338 | head = 1; | ||
339 | DBG("header : %d %d %d %d %d %d %d %d %d", | ||
340 | cam->buffer[0], cam->buffer[1], cam->buffer[2], | ||
341 | cam->buffer[3], cam->buffer[4], cam->buffer[5], | ||
342 | cam->buffer[6], cam->buffer[7], cam->buffer[8]); | ||
343 | } else { | ||
344 | memcpy(ptr, cam->buffer, actual_length); | ||
345 | ptr += actual_length; | ||
346 | } | ||
347 | } | ||
348 | /* ... until there is no more */ | ||
349 | while (actual_length == BUFFER_SIZE); | ||
350 | |||
351 | /* we skip the 2 first frames which are usually buggy */ | ||
352 | if (cam->skip) { | ||
353 | cam->skip--; | ||
354 | goto redo; | ||
355 | } | ||
356 | |||
357 | /* go back to find the JPEG EOI marker */ | ||
358 | size = ptr - jpeg; | ||
359 | ptr -= 2; | ||
360 | while (ptr > jpeg) { | ||
361 | if (*ptr == 0xFF && *(ptr + 1) == 0xD9 | ||
362 | && *(ptr + 2) == 0xFF) | ||
363 | break; | ||
364 | ptr--; | ||
365 | } | ||
366 | if (ptr == jpeg) | ||
367 | DBG("No EOI marker"); | ||
368 | |||
369 | /* Sometimes there is junk data in the middle of the picture, | ||
370 | * we want to skip this bogus frames */ | ||
371 | while (ptr > jpeg) { | ||
372 | if (*ptr == 0xFF && *(ptr + 1) == 0xFF | ||
373 | && *(ptr + 2) == 0xFF) | ||
374 | break; | ||
375 | ptr--; | ||
376 | } | ||
377 | if (ptr != jpeg) { | ||
378 | DBG("Bogus frame ? %d", cam->nb); | ||
379 | goto redo; | ||
380 | } | ||
381 | |||
382 | DBG("jpeg : %d %d %d %d %d %d %d %d", | ||
383 | jpeg[0], jpeg[1], jpeg[2], jpeg[3], | ||
384 | jpeg[4], jpeg[5], jpeg[6], jpeg[7]); | ||
385 | |||
386 | return size; | ||
387 | } | ||
388 | |||
389 | |||
390 | static ssize_t zr364xx_read(struct file *file, char *buf, size_t cnt, | ||
391 | loff_t * ppos) | ||
392 | { | ||
393 | unsigned long count = cnt; | ||
394 | struct video_device *vdev = video_devdata(file); | ||
395 | struct zr364xx_camera *cam; | ||
396 | |||
397 | DBG("zr364xx_read: read %d bytes.", (int) count); | ||
398 | |||
399 | if (vdev == NULL) | ||
400 | return -ENODEV; | ||
401 | cam = video_get_drvdata(vdev); | ||
402 | |||
403 | if (!buf) | ||
404 | return -EINVAL; | ||
405 | |||
406 | if (!count) | ||
407 | return -EINVAL; | ||
408 | |||
409 | /* NoMan Sux ! */ | ||
410 | count = read_frame(cam, 0); | ||
411 | |||
412 | if (copy_to_user(buf, cam->framebuf, count)) | ||
413 | return -EFAULT; | ||
414 | |||
415 | return count; | ||
416 | } | ||
417 | |||
418 | |||
419 | static int zr364xx_vidioc_querycap(struct file *file, void *priv, | ||
420 | struct v4l2_capability *cap) | ||
421 | { | ||
422 | memset(cap, 0, sizeof(*cap)); | ||
423 | strcpy(cap->driver, DRIVER_DESC); | ||
424 | cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE; | ||
425 | return 0; | ||
426 | } | ||
427 | |||
428 | static int zr364xx_vidioc_enum_input(struct file *file, void *priv, | ||
429 | struct v4l2_input *i) | ||
430 | { | ||
431 | if (i->index != 0) | ||
432 | return -EINVAL; | ||
433 | memset(i, 0, sizeof(*i)); | ||
434 | i->index = 0; | ||
435 | strcpy(i->name, DRIVER_DESC " Camera"); | ||
436 | i->type = V4L2_INPUT_TYPE_CAMERA; | ||
437 | return 0; | ||
438 | } | ||
439 | |||
440 | static int zr364xx_vidioc_g_input(struct file *file, void *priv, | ||
441 | unsigned int *i) | ||
442 | { | ||
443 | *i = 0; | ||
444 | return 0; | ||
445 | } | ||
446 | |||
447 | static int zr364xx_vidioc_s_input(struct file *file, void *priv, | ||
448 | unsigned int i) | ||
449 | { | ||
450 | if (i != 0) | ||
451 | return -EINVAL; | ||
452 | return 0; | ||
453 | } | ||
454 | |||
455 | static int zr364xx_vidioc_queryctrl(struct file *file, void *priv, | ||
456 | struct v4l2_queryctrl *c) | ||
457 | { | ||
458 | struct video_device *vdev = video_devdata(file); | ||
459 | struct zr364xx_camera *cam; | ||
460 | |||
461 | if (vdev == NULL) | ||
462 | return -ENODEV; | ||
463 | cam = video_get_drvdata(vdev); | ||
464 | |||
465 | switch (c->id) { | ||
466 | case V4L2_CID_BRIGHTNESS: | ||
467 | c->type = V4L2_CTRL_TYPE_INTEGER; | ||
468 | strcpy(c->name, "Brightness"); | ||
469 | c->minimum = 0; | ||
470 | c->maximum = 127; | ||
471 | c->step = 1; | ||
472 | c->default_value = cam->brightness; | ||
473 | c->flags = 0; | ||
474 | break; | ||
475 | default: | ||
476 | return -EINVAL; | ||
477 | } | ||
478 | return 0; | ||
479 | } | ||
480 | |||
481 | static int zr364xx_vidioc_s_ctrl(struct file *file, void *priv, | ||
482 | struct v4l2_control *c) | ||
483 | { | ||
484 | struct video_device *vdev = video_devdata(file); | ||
485 | struct zr364xx_camera *cam; | ||
486 | |||
487 | if (vdev == NULL) | ||
488 | return -ENODEV; | ||
489 | cam = video_get_drvdata(vdev); | ||
490 | |||
491 | switch (c->id) { | ||
492 | case V4L2_CID_BRIGHTNESS: | ||
493 | cam->brightness = c->value; | ||
494 | break; | ||
495 | default: | ||
496 | return -EINVAL; | ||
497 | } | ||
498 | return 0; | ||
499 | } | ||
500 | |||
501 | static int zr364xx_vidioc_g_ctrl(struct file *file, void *priv, | ||
502 | struct v4l2_control *c) | ||
503 | { | ||
504 | struct video_device *vdev = video_devdata(file); | ||
505 | struct zr364xx_camera *cam; | ||
506 | |||
507 | if (vdev == NULL) | ||
508 | return -ENODEV; | ||
509 | cam = video_get_drvdata(vdev); | ||
510 | |||
511 | switch (c->id) { | ||
512 | case V4L2_CID_BRIGHTNESS: | ||
513 | c->value = cam->brightness; | ||
514 | break; | ||
515 | default: | ||
516 | return -EINVAL; | ||
517 | } | ||
518 | return 0; | ||
519 | } | ||
520 | |||
521 | static int zr364xx_vidioc_enum_fmt_cap(struct file *file, | ||
522 | void *priv, struct v4l2_fmtdesc *f) | ||
523 | { | ||
524 | if (f->index > 0) | ||
525 | return -EINVAL; | ||
526 | if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
527 | return -EINVAL; | ||
528 | memset(f, 0, sizeof(*f)); | ||
529 | f->index = 0; | ||
530 | f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
531 | f->flags = V4L2_FMT_FLAG_COMPRESSED; | ||
532 | strcpy(f->description, "JPEG"); | ||
533 | f->pixelformat = V4L2_PIX_FMT_JPEG; | ||
534 | return 0; | ||
535 | } | ||
536 | |||
537 | static int zr364xx_vidioc_try_fmt_cap(struct file *file, void *priv, | ||
538 | struct v4l2_format *f) | ||
539 | { | ||
540 | struct video_device *vdev = video_devdata(file); | ||
541 | struct zr364xx_camera *cam; | ||
542 | |||
543 | if (vdev == NULL) | ||
544 | return -ENODEV; | ||
545 | cam = video_get_drvdata(vdev); | ||
546 | |||
547 | if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
548 | return -EINVAL; | ||
549 | if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG) | ||
550 | return -EINVAL; | ||
551 | if (f->fmt.pix.field != V4L2_FIELD_ANY && | ||
552 | f->fmt.pix.field != V4L2_FIELD_NONE) | ||
553 | return -EINVAL; | ||
554 | f->fmt.pix.field = V4L2_FIELD_NONE; | ||
555 | f->fmt.pix.width = cam->width; | ||
556 | f->fmt.pix.height = cam->height; | ||
557 | f->fmt.pix.bytesperline = f->fmt.pix.width * 2; | ||
558 | f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; | ||
559 | f->fmt.pix.colorspace = 0; | ||
560 | f->fmt.pix.priv = 0; | ||
561 | return 0; | ||
562 | } | ||
563 | |||
564 | static int zr364xx_vidioc_g_fmt_cap(struct file *file, void *priv, | ||
565 | struct v4l2_format *f) | ||
566 | { | ||
567 | struct video_device *vdev = video_devdata(file); | ||
568 | struct zr364xx_camera *cam; | ||
569 | |||
570 | if (vdev == NULL) | ||
571 | return -ENODEV; | ||
572 | cam = video_get_drvdata(vdev); | ||
573 | |||
574 | if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
575 | return -EINVAL; | ||
576 | memset(&f->fmt.pix, 0, sizeof(struct v4l2_pix_format)); | ||
577 | f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
578 | f->fmt.pix.pixelformat = V4L2_PIX_FMT_JPEG; | ||
579 | f->fmt.pix.field = V4L2_FIELD_NONE; | ||
580 | f->fmt.pix.width = cam->width; | ||
581 | f->fmt.pix.height = cam->height; | ||
582 | f->fmt.pix.bytesperline = f->fmt.pix.width * 2; | ||
583 | f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; | ||
584 | f->fmt.pix.colorspace = 0; | ||
585 | f->fmt.pix.priv = 0; | ||
586 | return 0; | ||
587 | } | ||
588 | |||
589 | static int zr364xx_vidioc_s_fmt_cap(struct file *file, void *priv, | ||
590 | struct v4l2_format *f) | ||
591 | { | ||
592 | struct video_device *vdev = video_devdata(file); | ||
593 | struct zr364xx_camera *cam; | ||
594 | |||
595 | if (vdev == NULL) | ||
596 | return -ENODEV; | ||
597 | cam = video_get_drvdata(vdev); | ||
598 | |||
599 | if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
600 | return -EINVAL; | ||
601 | if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG) | ||
602 | return -EINVAL; | ||
603 | if (f->fmt.pix.field != V4L2_FIELD_ANY && | ||
604 | f->fmt.pix.field != V4L2_FIELD_NONE) | ||
605 | return -EINVAL; | ||
606 | f->fmt.pix.field = V4L2_FIELD_NONE; | ||
607 | f->fmt.pix.width = cam->width; | ||
608 | f->fmt.pix.height = cam->height; | ||
609 | f->fmt.pix.bytesperline = f->fmt.pix.width * 2; | ||
610 | f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; | ||
611 | f->fmt.pix.colorspace = 0; | ||
612 | f->fmt.pix.priv = 0; | ||
613 | DBG("ok!"); | ||
614 | return 0; | ||
615 | } | ||
616 | |||
617 | static int zr364xx_vidioc_streamon(struct file *file, void *priv, | ||
618 | enum v4l2_buf_type type) | ||
619 | { | ||
620 | return 0; | ||
621 | } | ||
622 | |||
623 | static int zr364xx_vidioc_streamoff(struct file *file, void *priv, | ||
624 | enum v4l2_buf_type type) | ||
625 | { | ||
626 | return 0; | ||
627 | } | ||
628 | |||
629 | |||
630 | /* open the camera */ | ||
631 | static int zr364xx_open(struct inode *inode, struct file *file) | ||
632 | { | ||
633 | struct video_device *vdev = video_devdata(file); | ||
634 | struct zr364xx_camera *cam = video_get_drvdata(vdev); | ||
635 | struct usb_device *udev = cam->udev; | ||
636 | int i, err; | ||
637 | |||
638 | DBG("zr364xx_open"); | ||
639 | |||
640 | cam->skip = 2; | ||
641 | |||
642 | err = video_exclusive_open(inode, file); | ||
643 | if (err < 0) | ||
644 | return err; | ||
645 | |||
646 | if (!cam->framebuf) { | ||
647 | cam->framebuf = vmalloc_32(MAX_FRAME_SIZE * FRAMES); | ||
648 | if (!cam->framebuf) { | ||
649 | info("vmalloc_32 failed!"); | ||
650 | return -ENOMEM; | ||
651 | } | ||
652 | } | ||
653 | |||
654 | mutex_lock(&cam->lock); | ||
655 | for (i = 0; init[cam->method][i].size != -1; i++) { | ||
656 | err = | ||
657 | send_control_msg(udev, 1, init[cam->method][i].value, | ||
658 | 0, init[cam->method][i].bytes, | ||
659 | init[cam->method][i].size); | ||
660 | if (err < 0) { | ||
661 | info("error during open sequence: %d", i); | ||
662 | mutex_unlock(&cam->lock); | ||
663 | return err; | ||
664 | } | ||
665 | } | ||
666 | |||
667 | file->private_data = vdev; | ||
668 | |||
669 | /* Added some delay here, since opening/closing the camera quickly, | ||
670 | * like Ekiga does during its startup, can crash the webcam | ||
671 | */ | ||
672 | mdelay(100); | ||
673 | |||
674 | mutex_unlock(&cam->lock); | ||
675 | return 0; | ||
676 | } | ||
677 | |||
678 | |||
679 | /* release the camera */ | ||
680 | static int zr364xx_release(struct inode *inode, struct file *file) | ||
681 | { | ||
682 | struct video_device *vdev = video_devdata(file); | ||
683 | struct zr364xx_camera *cam; | ||
684 | struct usb_device *udev; | ||
685 | int i, err; | ||
686 | |||
687 | DBG("zr364xx_release"); | ||
688 | |||
689 | if (vdev == NULL) | ||
690 | return -ENODEV; | ||
691 | cam = video_get_drvdata(vdev); | ||
692 | |||
693 | udev = cam->udev; | ||
694 | |||
695 | mutex_lock(&cam->lock); | ||
696 | for (i = 0; i < 2; i++) { | ||
697 | err = | ||
698 | send_control_msg(udev, 1, init[cam->method][i].value, | ||
699 | 0, init[i][cam->method].bytes, | ||
700 | init[cam->method][i].size); | ||
701 | if (err < 0) { | ||
702 | info("error during release sequence"); | ||
703 | mutex_unlock(&cam->lock); | ||
704 | return err; | ||
705 | } | ||
706 | } | ||
707 | |||
708 | file->private_data = NULL; | ||
709 | video_exclusive_release(inode, file); | ||
710 | |||
711 | /* Added some delay here, since opening/closing the camera quickly, | ||
712 | * like Ekiga does during its startup, can crash the webcam | ||
713 | */ | ||
714 | mdelay(100); | ||
715 | |||
716 | mutex_unlock(&cam->lock); | ||
717 | return 0; | ||
718 | } | ||
719 | |||
720 | |||
721 | static int zr364xx_mmap(struct file *file, struct vm_area_struct *vma) | ||
722 | { | ||
723 | void *pos; | ||
724 | unsigned long start = vma->vm_start; | ||
725 | unsigned long size = vma->vm_end - vma->vm_start; | ||
726 | struct video_device *vdev = video_devdata(file); | ||
727 | struct zr364xx_camera *cam; | ||
728 | |||
729 | DBG("zr364xx_mmap: %ld\n", size); | ||
730 | |||
731 | if (vdev == NULL) | ||
732 | return -ENODEV; | ||
733 | cam = video_get_drvdata(vdev); | ||
734 | |||
735 | pos = cam->framebuf; | ||
736 | while (size > 0) { | ||
737 | if (vm_insert_page(vma, start, vmalloc_to_page(pos))) | ||
738 | return -EAGAIN; | ||
739 | start += PAGE_SIZE; | ||
740 | pos += PAGE_SIZE; | ||
741 | if (size > PAGE_SIZE) | ||
742 | size -= PAGE_SIZE; | ||
743 | else | ||
744 | size = 0; | ||
745 | } | ||
746 | |||
747 | return 0; | ||
748 | } | ||
749 | |||
750 | |||
751 | static struct file_operations zr364xx_fops = { | ||
752 | .owner = THIS_MODULE, | ||
753 | .open = zr364xx_open, | ||
754 | .release = zr364xx_release, | ||
755 | .read = zr364xx_read, | ||
756 | .mmap = zr364xx_mmap, | ||
757 | .ioctl = video_ioctl2, | ||
758 | .llseek = no_llseek, | ||
759 | }; | ||
760 | |||
761 | static struct video_device zr364xx_template = { | ||
762 | .owner = THIS_MODULE, | ||
763 | .name = DRIVER_DESC, | ||
764 | .type = VID_TYPE_CAPTURE, | ||
765 | .fops = &zr364xx_fops, | ||
766 | .release = video_device_release, | ||
767 | .minor = -1, | ||
768 | |||
769 | .vidioc_querycap = zr364xx_vidioc_querycap, | ||
770 | .vidioc_enum_fmt_cap = zr364xx_vidioc_enum_fmt_cap, | ||
771 | .vidioc_try_fmt_cap = zr364xx_vidioc_try_fmt_cap, | ||
772 | .vidioc_s_fmt_cap = zr364xx_vidioc_s_fmt_cap, | ||
773 | .vidioc_g_fmt_cap = zr364xx_vidioc_g_fmt_cap, | ||
774 | .vidioc_enum_input = zr364xx_vidioc_enum_input, | ||
775 | .vidioc_g_input = zr364xx_vidioc_g_input, | ||
776 | .vidioc_s_input = zr364xx_vidioc_s_input, | ||
777 | .vidioc_streamon = zr364xx_vidioc_streamon, | ||
778 | .vidioc_streamoff = zr364xx_vidioc_streamoff, | ||
779 | .vidioc_queryctrl = zr364xx_vidioc_queryctrl, | ||
780 | .vidioc_g_ctrl = zr364xx_vidioc_g_ctrl, | ||
781 | .vidioc_s_ctrl = zr364xx_vidioc_s_ctrl, | ||
782 | }; | ||
783 | |||
784 | |||
785 | |||
786 | /*******************/ | ||
787 | /* USB integration */ | ||
788 | /*******************/ | ||
789 | |||
790 | static int zr364xx_probe(struct usb_interface *intf, | ||
791 | const struct usb_device_id *id) | ||
792 | { | ||
793 | struct usb_device *udev = interface_to_usbdev(intf); | ||
794 | struct zr364xx_camera *cam = NULL; | ||
795 | |||
796 | DBG("probing..."); | ||
797 | |||
798 | info(DRIVER_DESC " compatible webcam plugged"); | ||
799 | info("model %04x:%04x detected", udev->descriptor.idVendor, | ||
800 | udev->descriptor.idProduct); | ||
801 | |||
802 | if ((cam = | ||
803 | kmalloc(sizeof(struct zr364xx_camera), GFP_KERNEL)) == NULL) { | ||
804 | info("cam: out of memory !"); | ||
805 | return -ENODEV; | ||
806 | } | ||
807 | memset(cam, 0x00, sizeof(struct zr364xx_camera)); | ||
808 | /* save the init method used by this camera */ | ||
809 | cam->method = id->driver_info; | ||
810 | |||
811 | cam->vdev = video_device_alloc(); | ||
812 | if (cam->vdev == NULL) { | ||
813 | info("cam->vdev: out of memory !"); | ||
814 | kfree(cam); | ||
815 | return -ENODEV; | ||
816 | } | ||
817 | memcpy(cam->vdev, &zr364xx_template, sizeof(zr364xx_template)); | ||
818 | video_set_drvdata(cam->vdev, cam); | ||
819 | if (debug) | ||
820 | cam->vdev->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG; | ||
821 | |||
822 | cam->udev = udev; | ||
823 | |||
824 | if ((cam->buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL)) == NULL) { | ||
825 | info("cam->buffer: out of memory !"); | ||
826 | video_device_release(cam->vdev); | ||
827 | kfree(cam); | ||
828 | return -ENODEV; | ||
829 | } | ||
830 | |||
831 | switch (mode) { | ||
832 | case 1: | ||
833 | info("160x120 mode selected"); | ||
834 | cam->width = 160; | ||
835 | cam->height = 120; | ||
836 | break; | ||
837 | case 2: | ||
838 | info("640x480 mode selected"); | ||
839 | cam->width = 640; | ||
840 | cam->height = 480; | ||
841 | break; | ||
842 | default: | ||
843 | info("320x240 mode selected"); | ||
844 | cam->width = 320; | ||
845 | cam->height = 240; | ||
846 | break; | ||
847 | } | ||
848 | |||
849 | m0d1[0] = mode; | ||
850 | m1[2].value = 0xf000 + mode; | ||
851 | m2[1].value = 0xf000 + mode; | ||
852 | header2[437] = cam->height / 256; | ||
853 | header2[438] = cam->height % 256; | ||
854 | header2[439] = cam->width / 256; | ||
855 | header2[440] = cam->width % 256; | ||
856 | |||
857 | cam->nb = 0; | ||
858 | cam->brightness = 64; | ||
859 | mutex_init(&cam->lock); | ||
860 | |||
861 | if (video_register_device(cam->vdev, VFL_TYPE_GRABBER, -1) == -1) { | ||
862 | info("video_register_device failed"); | ||
863 | video_device_release(cam->vdev); | ||
864 | kfree(cam->buffer); | ||
865 | kfree(cam); | ||
866 | return -ENODEV; | ||
867 | } | ||
868 | |||
869 | usb_set_intfdata(intf, cam); | ||
870 | |||
871 | info(DRIVER_DESC " controlling video device %d", cam->vdev->minor); | ||
872 | return 0; | ||
873 | } | ||
874 | |||
875 | |||
876 | static void zr364xx_disconnect(struct usb_interface *intf) | ||
877 | { | ||
878 | struct zr364xx_camera *cam = usb_get_intfdata(intf); | ||
879 | usb_set_intfdata(intf, NULL); | ||
880 | dev_set_drvdata(&intf->dev, NULL); | ||
881 | info(DRIVER_DESC " webcam unplugged"); | ||
882 | if (cam->vdev) | ||
883 | video_unregister_device(cam->vdev); | ||
884 | cam->vdev = NULL; | ||
885 | kfree(cam->buffer); | ||
886 | if (cam->framebuf) | ||
887 | vfree(cam->framebuf); | ||
888 | kfree(cam); | ||
889 | } | ||
890 | |||
891 | |||
892 | |||
893 | /**********************/ | ||
894 | /* Module integration */ | ||
895 | /**********************/ | ||
896 | |||
897 | static struct usb_driver zr364xx_driver = { | ||
898 | .name = "zr364xx", | ||
899 | .probe = zr364xx_probe, | ||
900 | .disconnect = zr364xx_disconnect, | ||
901 | .id_table = device_table | ||
902 | }; | ||
903 | |||
904 | |||
905 | static int __init zr364xx_init(void) | ||
906 | { | ||
907 | int retval; | ||
908 | retval = usb_register(&zr364xx_driver) < 0; | ||
909 | if (retval) | ||
910 | info("usb_register failed!"); | ||
911 | else | ||
912 | info(DRIVER_DESC " module loaded"); | ||
913 | return retval; | ||
914 | } | ||
915 | |||
916 | |||
917 | static void __exit zr364xx_exit(void) | ||
918 | { | ||
919 | info(DRIVER_DESC " module unloaded"); | ||
920 | usb_deregister(&zr364xx_driver); | ||
921 | } | ||
922 | |||
923 | |||
924 | module_init(zr364xx_init); | ||
925 | module_exit(zr364xx_exit); | ||
926 | |||
927 | MODULE_AUTHOR(DRIVER_AUTHOR); | ||
928 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
929 | MODULE_LICENSE("GPL"); | ||