diff options
-rw-r--r-- | linux/drivers/media/video/em28xx/em28xx-cards.c | 2 | ||||
-rw-r--r-- | linux/drivers/media/video/em28xx/em28xx-i2c.c | 1 | ||||
-rw-r--r-- | linux/drivers/media/video/tuner-core.c | 1 | ||||
-rw-r--r-- | linux/drivers/media/video/xc3028.c | 236 | ||||
-rw-r--r-- | v4l_experimental/xc3028/convert.c | 7 |
5 files changed, 243 insertions, 4 deletions
diff --git a/linux/drivers/media/video/em28xx/em28xx-cards.c b/linux/drivers/media/video/em28xx/em28xx-cards.c index dbaf5f207..9830404e5 100644 --- a/linux/drivers/media/video/em28xx/em28xx-cards.c +++ b/linux/drivers/media/video/em28xx/em28xx-cards.c @@ -182,8 +182,8 @@ struct em28xx_board em28xx_boards[] = { .vchannels = 3, .norm = VIDEO_MODE_PAL, .tda9887_conf = TDA9887_PRESENT, - .tuner_type = TUNER_XCEIVE_XC3028, .has_tuner = 1, + .tuner_type = TUNER_XCEIVE_XC3028, .decoder = EM28XX_TVP5150, .input = {{ .type = EM28XX_VMUX_COMPOSITE1, diff --git a/linux/drivers/media/video/em28xx/em28xx-i2c.c b/linux/drivers/media/video/em28xx/em28xx-i2c.c index 75f36e371..59b13ff37 100644 --- a/linux/drivers/media/video/em28xx/em28xx-i2c.c +++ b/linux/drivers/media/video/em28xx/em28xx-i2c.c @@ -420,7 +420,6 @@ static int em28xx_set_tuner(int check_eeprom, struct i2c_client *client) tun_setup.mode_mask = T_ANALOG_TV | T_RADIO; tun_setup.type = dev->tuner_type; tun_setup.addr = dev->tuner_addr; - em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup); } diff --git a/linux/drivers/media/video/tuner-core.c b/linux/drivers/media/video/tuner-core.c index bc559b9d7..fb684fdb0 100644 --- a/linux/drivers/media/video/tuner-core.c +++ b/linux/drivers/media/video/tuner-core.c @@ -202,7 +202,6 @@ static void set_type(struct i2c_client *c, unsigned int type, #endif t->type = type; - switch (t->type) { case TUNER_MT2032: microtune_init(c); diff --git a/linux/drivers/media/video/xc3028.c b/linux/drivers/media/video/xc3028.c new file mode 100644 index 000000000..a2d5df4c0 --- /dev/null +++ b/linux/drivers/media/video/xc3028.c @@ -0,0 +1,236 @@ +/* + + Xceive - xc3028 tuner interface + + Copyright (c) 2006 Markus Rechberger <mrechberger@gmail.com> + + +TODO: - remove em28xx dependency + - add channel locking (requires some more reverse engineering) + - try to get the datasheet from Xceive :) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include <linux/i2c.h> +#include <linux/usb.h> +#include "compat.h" +#include <linux/videodev.h> +#include "em28xx.h" +#include <linux/firmware.h> +#include <linux/delay.h> +#include <media/tuner.h> +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +#include "i2c-compat.h" +#endif + +#define XC3028_DEFAULT_FIRMWARE "xceive_xc_3028.fw" + +int xceive_set_color(struct i2c_client *c); + +/* ---------------------------------------------------------------------- */ + +int xc3028_probe(struct i2c_client *c) +{ + printk("xc3028: probe function unknown\n"); + return -1; +} + +static void xc3028_set_tv_freq(struct i2c_client *c, unsigned int freq){ + /* + the frequency is just shifted and there's a 1:1 relation for all frequencies + E11 is Das Erste in Germany/Ulm all other channels match their frequency too + */ + + unsigned char chanbuf[4]; + freq<<=2; + chanbuf[0]=0; + chanbuf[1]=0; + chanbuf[2]=(freq&0xff00)>>8; + chanbuf[3]=freq&0x00ff; + i2c_master_send(c,"\xa0\x00\x00\x00",4); + i2c_master_send(c,"\x1e\x1f\x13\x87\x18\x02\x93\x91\x44\x86\x96\x8c",12); + i2c_master_send(c,"\x00\x8c",2); + i2c_master_send(c,"\x80\x02\x00\x00",4); + i2c_master_send(c,chanbuf,4); +} + +int xc3028_init(struct i2c_client *c) +{ + struct tuner *t = i2c_get_clientdata(c); + struct em28xx *dev; + const struct firmware *fw = NULL; + size_t firmware_size; + int ret=-1; + int i=0; + int d=0; + int txtlen; + long fwoff; + u8 *firmware; + u8 linebuffer[100]; + char *fwoffset; + + /* + request firmware from /lib/firmware, note that the file got extracted by the convert application I wrote and which is available + on linuxtv.org / xc3028 + */ + + ret = request_firmware(&fw, XC3028_DEFAULT_FIRMWARE, &t->i2c.dev); + if (ret) { + printk("xc3028: no firmware uploaded please check %s\n",XC3028_DEFAULT_FIRMWARE); + return ret; + } + firmware = fw->data; + firmware_size = fw->size; + + /* small firmware check, both firmwares I have are between 6 and 7k bytes */ + + if(fw->size>7000||fw->size<6000){ + printk("xc3028: wrong firmware provided!\n"); + release_firmware(fw); + return(ret); + } + for(i=0;i<8&&firmware[i]!='\n';i++); + txtlen=i; + firmware[i++]=0; + fwoff=simple_strtol(firmware,&fwoffset,10); + if(fwoff>fw->size){ + printk("xc3028: firmware offset doesn't match!\n"); + release_firmware(fw); + return(-1); + } + + linebuffer[d++]=0x2a; + dev=c->adapter->algo_data; + + /* 0x08 is a GPIO address of the em28xx has to get replaced with something generic here */ + + dev->em28xx_write_regs(dev, 0x08, "\x6d", 1); + dev->em28xx_write_regs(dev, 0x08, "\x7d", 1); + + /* + the firmware always starts with 0x2a + 0x40 bytes payload I use to add the offset of the first part + as the first line into the firmware binary + */ + while(i!=fw->size){ + linebuffer[d++]=firmware[i]; + if((d%64==0&&d!=0)||i==fwoff+txtlen){ + i2c_master_send(c,linebuffer,d); + if(i==(fwoff+txtlen)){ + i2c_master_send(c,"\x02\x02",2); + i2c_master_send(c,"\x02\x03",2); + i2c_master_send(c,"\x00\x8c",2); + i2c_master_send(c,"\x00\x00\x00\x00",4); + /* at least 100 ms delay here, if less terratec FW won't work */ + msleep(100); + /* another reset here */ + dev->em28xx_write_regs(dev, 0x08, "\x6d", 1); + dev->em28xx_write_regs(dev, 0x08, "\x7d", 1); + + } + linebuffer[0]=0x2a; + d=1; + } + i++; + } + printk("xc3024: Firmware uploaded\n"); + release_firmware(fw); + + /* MAGIC VALUES Hauppauge */ + i2c_master_send(c,"\x13\x39",2); + i2c_master_send(c,"\x0c\x80\xf0\xf7\x3e\x75\xc1\x8a\xe4\x02\x00",11); + i2c_master_send(c,"\x05\x0f\xee\xaa\x5f\xea\x90",7); + i2c_master_send(c,"\x06\x00\x0a\x4d\x8c\xf2\xd8\xcf\x30\x79\x9f",11); + i2c_master_send(c,"\x0b\x0d\xa4\x6c",4); + i2c_master_send(c,"\x0a\x01\x67\x24\x40\x08\xc3\x20\x10\x64\x3c\xfa\xf7\xe1\x0c\x2c",0x10); + i2c_master_send(c,"\x09\x0b",0x2); + i2c_master_send(c,"\x10\x13",0x2); + i2c_master_send(c,"\x16\x12",0x2); + i2c_master_send(c,"\x1f\x02",0x2); + i2c_master_send(c,"\x21\x02",0x2); + i2c_master_send(c,"\x01\x02",0x2); + i2c_master_send(c,"\x2b\x10",0x2); + i2c_master_send(c,"\x02\x02",0x2); + i2c_master_send(c,"\x02\x03",0x2); + i2c_master_send(c,"\x00\x8c",0x2); + +#if 0 + /* MAGIC Values Terratec - dvb init*/ + i2c_master_send(c,"\x13\x39",0x02); + i2c_master_send(c,"\x0c\x80\xf0\xf7\x3e\x75\xc1\x8a\xe4\x02\x00",11); + i2c_master_send(c,"\x05\x0f\xee\xaa\x5f\xea\x90",7); + i2c_master_send(c,"\x06\x00\x0a\x4d\x8c\xf2\xd8\xcf\x30\x79\x9f",11); + i2c_master_send(c,"\x0b\x0d\xa4\x6c",4); + i2c_master_send(c,"\x0a\x01\x67\x24\x40\x08\xc3\x20\x10\x64\x3c\xfa\xf7\xe1\x0c\x2c",0x10); + i2c_master_send(c,"\x09\x0b",0x02); + i2c_master_send(c,"\x10\x13",0x02); + i2c_master_send(c,"\x16\x12",0x02); + i2c_master_send(c,"\x1f\x02",0x02); + i2c_master_send(c,"\x21\x02",0x02); + i2c_master_send(c,"\x01\x02",0x02); + i2c_master_send(c,"\x2b\x10",0x02); + i2c_master_send(c,"\x02\x02",0x02); + i2c_master_send(c,"\x02\x03",0x02); + i2c_master_send(c,"\x00\x8c",0x02); +#endif +#if 0 + /* if set video will mostly be black/white - if set_color is called instead the video will have color */ + i2c_master_send(c,"\x80\x01\x00\x00",0x4); + i2c_master_send(c,"\x00\x5e\x00\x29",0x4); + i2c_master_send(c,"\x2b\x1a",0x2); +#endif + xceive_set_color(c); + t->set_tv_freq = xc3028_set_tv_freq; + return(0); +} + +int xceive_set_color(struct i2c_client *c){ + /* I found this codeblock within the sniffed logfile it got called as it is a several times after 0x00 0x04 tuner settings are made */ + /* codeblock hauppauge/terratec - analog */ + i2c_master_send(c,"\x80\x01\x00\x00",4); + i2c_master_send(c,"\x00\x5e\x00\x29",4); + i2c_master_send(c,"\x2b\x1a",2); + i2c_master_send(c,"\x2b\x1b",2); + i2c_master_send(c,"\x14\x01\x6c\x25\x82\x38\xa4\x49\xa9\x24\x96\x69",0x0c); + i2c_master_send(c,"\x13\x14\x08\x30\x10\x6c\x18\x12\x0d\x19\x32\xad",0x0c); + i2c_master_send(c,"\x0d\x01\x4b\x03\x97\x55\xc7\xd7\x00\xa1\xeb\x8f\x5c",0x0d); + i2c_master_send(c,"\x1a\x00\x00\x16\x8a\x40\x00\x00\x00\x20",0x0a); + i2c_master_send(c,"\x2d\x01",2); + i2c_master_send(c,"\x18\x01",2); + i2c_master_send(c,"\x1b\x01\xb6\x15\x16\xb1\xa6\xd2\xa9\x12\x41\x66",0x0c); + i2c_master_send(c,"\x1d\x00",2); + i2c_master_send(c,"\x0f\x00\x29\x56\xb0\x00\xb6",0x07); + i2c_master_send(c,"\x20\x00",0x02); + i2c_master_send(c,"\x1e\x10\x32\x00\x00\x02\xe4\x81\x00\x06\xa9\x04",0x0c); + i2c_master_send(c,"\x22\x29",0x02); + i2c_master_send(c,"\x23\x06",0x02); + i2c_master_send(c,"\x25\x00\x09\x90\x09\x06\x64\x02\x41",0x09); + i2c_master_send(c,"\x26\xcc",0x02); + i2c_master_send(c,"\x29\x40",0x02); + i2c_master_send(c,"\x21\x03",0x02); + i2c_master_send(c,"\x00\x8c",0x02); + i2c_master_send(c,"\x00\x00\x00\x00",0x04); /* just wonder no sleep here regarding the logs */ + i2c_master_send(c,"\x00\x04",0x02); + return(0); +} + + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/v4l_experimental/xc3028/convert.c b/v4l_experimental/xc3028/convert.c index 00b1f7d9d..2559bba5e 100644 --- a/v4l_experimental/xc3028/convert.c +++ b/v4l_experimental/xc3028/convert.c @@ -3,13 +3,14 @@ #include <stdlib.h> #define ARRAY_SIZE(fw) sizeof(fw)/sizeof(fw[0]) + struct{ char *fwname; char *fwstart; char *fwstart2; int length1; int length2; -} xc_firmware[]={{"Terratec","\x2a\x03\xe5\xe0\x00\x07\xf4\xd0\x01\xc0\x70\xe0\x00\x07","\x2a\x00\xc3\xe0\x00\x07\xb9\xf1\x05\x01\x6e\x82\x02\x82",2480,3876}, +} xc_firmware[]={{"Terratec","\x2a\x03\xe5\xe0\x00\x07\xf4\xd0\x01\xc0\x70\xe0\x00\x07","\x2a\x00\xbc\xe0\x00\x07\xb0\xf1\x05\x01\x67\x82\x02\x82",2480,3890}, {"Hauppauge","\x2a\x03\xcc\xe0\x00\x07\xf4\xd0\x01\xc0\x70\xe0\x00\x07","\x2a\x00\xbe\xe0\x00\x07\xb9\xf1\x05\x01\x69\x82\x02\x82",2532,3886}}; int main(int argc, char **argv){ @@ -29,6 +30,10 @@ int main(int argc, char **argv){ exit(1); } file=fopen(argv[1],"r"); + if(!file){ + printf("unable to open file\n"); + exit(1); + } fprintf(stderr,"Firmware extractor 0.1\n"); while((len=fread(buffer,1,1024,file))){ fleng+=len; |