dect
/
linux-2.6
Archived
13
0
Fork 0

V4L/DVB (6431): Improve firmware format

Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
This commit is contained in:
Mauro Carvalho Chehab 2007-10-24 09:22:08 -03:00
parent 215b95baf9
commit de3fe21ba2
3 changed files with 461 additions and 117 deletions

View File

@ -0,0 +1,99 @@
/* tuner-xc2028_types
*
* Copyright (c) 2007 Mauro Carvalho Chehab (mchehab@infradead.org)
* This code is placed under the terms of the GNU General Public License v2
*/
/* xc3028 firmware types */
/* BASE firmware should be loaded before any other firmware */
#define BASE (1<<0)
/* F8MHZ marks BASE firmwares for 8 MHz Bandwidth */
#define F8MHZ (1<<1)
/* Multichannel Television Sound (MTS)
Those firmwares are capable of using xc2038 DSP to decode audio and
produce a baseband audio output on some pins of the chip.
There are MTS firmwares for the most used video standards. It should be
required to use MTS firmwares, depending on the way audio is routed into
the bridge chip
*/
#define MTS (1<<2)
/* FIXME: I have no idea what's the difference between
D2620 and D2633 firmwares
*/
#define D2620 (1<<3)
#define D2633 (1<<4)
/* DTV firmwares for 6, 7 and 8 MHz
DTV6 - 6MHz - ATSC/DVB-C/DVB-T/ISDB-T/DOCSIS
DTV8 - 8MHz - DVB-C/DVB-T
*/
#define DTV6_ATSC (1<<5)
#define DTV6_QAM (1<<6)
#define DTV7 (1<<7)
#define DTV78 (1<<8)
#define DTV8 (1<<9)
/* There's a FM | BASE firmware + FM specific firmware (std=0) */
#define FM (1<<10)
/* Applies only for FM firmware
Makes it use RF input 1 (pin #2) instead of input 2 (pin #4)
*/
#define INPUT1 (1<<11)
/* LCD firmwares exist only for MTS STD/MN (PAL or NTSC/M)
and for non-MTS STD/MN (PAL, NTSC/M or NTSC/Kr)
There are variants both with and without NOGD
*/
#define LCD (1<<12)
/* NOGD firmwares exist only for MTS STD/MN (PAL or NTSC/M)
and for non-MTS STD/MN (PAL, NTSC/M or NTSC/Kr)
*/
#define NOGD (1<<13)
/* Old firmwares were broken into init0 and init1 */
#define INIT1 (1<<14)
/* Newer types to be moved to videodev2.h */
#define V4L2_STD_SECAM_K3 (0x02000000)
/* Audio types */
#define V4L2_STD_A2_A (1L<<32)
#define V4L2_STD_A2_B (1L<<33)
#define V4L2_STD_NICAM_A (1L<<34)
#define V4L2_STD_NICAM_B (1L<<35)
#define V4L2_STD_AM (1L<<36)
#define V4L2_STD_BTSC (1L<<37)
#define V4L2_STD__EIAJ (1L<<38)
#define V4L2_STD_A2 (V4L2_STD_A2_A | V4L2_STD_A2_B)
#define V4L2_STD_NICAM (V4L2_STD_NICAM_A | V4L2_STD_NICAM_B)
/* To preserve backward compatibilty,
(std & V4L2_STD_AUDIO) = 0 means that ALL audio stds are supported
*/
#define V4L2_STD_AUDIO (V4L2_STD_A2 | \
V4L2_STD_NICAM | \
V4L2_STD_AM | \
V4L2_STD_BTSC | \
V4L2_STD_EIAJ)
/* Used standards with audio restrictions */
#define V4L2_STD_PAL_BG_A2_A (V4L2_STD_PAL_BG | V4L2_STD_A2_A)
#define V4L2_STD_PAL_BG_A2_B (V4L2_STD_PAL_BG | V4L2_STD_A2_B)
#define V4L2_STD_PAL_BG_NICAM_A (V4L2_STD_PAL_BG | V4L2_STD_NICAM_A)
#define V4L2_STD_PAL_BG_NICAM_B (V4L2_STD_PAL_BG | V4L2_STD_NICAM_B)
#define V4L2_STD_PAL_DK_A2 (V4L2_STD_PAL_DK | V4L2_STD_A2)
#define V4L2_STD_PAL_DK_NICAM (V4L2_STD_PAL_DK | V4L2_STD_NICAM)
#define V4L2_STD_SECAM_L_NICAM (V4L2_STD_SECAM_L | V4L2_STD_NICAM)
#define V4L2_STD_SECAM_L_AM (V4L2_STD_SECAM_L | V4L2_STD_AM)

View File

@ -15,6 +15,7 @@
#include <linux/mutex.h> #include <linux/mutex.h>
#include "tuner-i2c.h" #include "tuner-i2c.h"
#include "tuner-xc2028.h" #include "tuner-xc2028.h"
#include "tuner-xc2028-types.h"
#include <linux/dvb/frontend.h> #include <linux/dvb/frontend.h>
#include "dvb_frontend.h" #include "dvb_frontend.h"
@ -22,21 +23,13 @@
#define PREFIX "xc2028 " #define PREFIX "xc2028 "
static LIST_HEAD(xc2028_list); static LIST_HEAD(xc2028_list);
/* struct for storing firmware table */
/* Firmwares used on tm5600/tm6000 + xc2028/xc3028 */ struct firmware_description {
unsigned int type;
/* Generic firmwares */ v4l2_std_id id;
static const char *firmware_INIT0 = "tm_xc3028_MTS_init0.fw"; unsigned char *ptr;
static const char *firmware_8MHZ_INIT0 = "tm_xc3028_8M_MTS_init0.fw"; unsigned int size;
static const char *firmware_INIT1 = "tm_xc3028_68M_MTS_init1.fw"; };
/* Standard-specific firmwares */
static const char *firmware_6M = "tm_xc3028_DTV_6M.fw";
static const char *firmware_7M = "tm_xc3028_DTV_7M.fw";
static const char *firmware_8M = "tm_xc3028_DTV_8M.fw";
static const char *firmware_B = "tm_xc3028_B_PAL.fw";
static const char *firmware_DK = "tm_xc3028_DK_PAL_MTS.fw";
static const char *firmware_MN = "tm_xc3028_MN_BTSC.fw";
struct xc2028_data { struct xc2028_data {
struct list_head xc2028_list; struct list_head xc2028_list;
@ -46,7 +39,14 @@ struct xc2028_data {
struct device *dev; struct device *dev;
void *video_dev; void *video_dev;
int count; int count;
u32 frequency; __u32 frequency;
struct firmware_description *firm;
int firm_size;
__u16 version;
struct xc2028_ctrl ctrl;
v4l2_std_id firm_type; /* video stds supported v4l2_std_id firm_type; /* video stds supported
by current firmware */ by current firmware */
@ -54,6 +54,9 @@ struct xc2028_data {
6M, 7M or 8M */ 6M, 7M or 8M */
int need_load_generic; /* The generic firmware int need_load_generic; /* The generic firmware
were loaded? */ were loaded? */
int max_len; /* Max firmware chunk */
enum tuner_mode mode; enum tuner_mode mode;
struct i2c_client *i2c_client; struct i2c_client *i2c_client;
@ -102,92 +105,263 @@ static int xc2028_get_reg(struct xc2028_data *priv, u16 reg)
return (buf[1])|(buf[0]<<8); return (buf[1])|(buf[0]<<8);
} }
static int load_firmware (struct dvb_frontend *fe, const char *name) static void free_firmware (struct xc2028_data *priv)
{ {
struct xc2028_data *priv = fe->tuner_priv; int i;
if (!priv->firm)
return;
for (i=0;i<priv->firm_size;i++) {
if (priv->firm[i].ptr)
kfree(priv->firm[i].ptr);
}
kfree(priv->firm);
priv->firm=NULL;
priv->need_load_generic = 1;
}
static int load_all_firmwares (struct dvb_frontend *fe)
{
struct xc2028_data *priv = fe->tuner_priv;
const struct firmware *fw=NULL; const struct firmware *fw=NULL;
unsigned char *p, *endp; unsigned char *p, *endp;
int len=0, rc=0; int rc=0, n, n_array;
static const char firmware_ver[] = "tm6000/xcv v1"; char name[33];
tuner_info("%s called\n", __FUNCTION__); tuner_info("%s called\n", __FUNCTION__);
tuner_info("Loading firmware %s\n", name); tuner_info("Loading firmware %s\n", priv->ctrl.fname);
rc = request_firmware(&fw, name, priv->dev); rc = request_firmware(&fw, priv->ctrl.fname, priv->dev);
if (rc < 0) { if (rc < 0) {
if (rc==-ENOENT) if (rc==-ENOENT)
tuner_info("Error: firmware %s not found.\n", name); tuner_info("Error: firmware %s not found.\n",
priv->ctrl.fname);
else else
tuner_info("Error %d while requesting firmware %s \n", rc, name); tuner_info("Error %d while requesting firmware %s \n",
rc, priv->ctrl.fname);
return rc; return rc;
} }
p=fw->data; p=fw->data;
endp=p+fw->size; endp=p+fw->size;
if(fw->size==0) { if(fw->size<sizeof(name)-1+2) {
tuner_info("Error: firmware size is zero!\n"); tuner_info("Error: firmware size is zero!\n");
rc=-EINVAL; rc=-EINVAL;
goto err; goto done;
}
if (fw->size<sizeof(firmware_ver)-1) {
/* Firmware is incorrect */
tuner_info("Error: firmware size is less than header (%d<%d)!\n",
(int)fw->size,(int)sizeof(firmware_ver)-1);
rc=-EINVAL;
goto err;
} }
if (memcmp(p,firmware_ver,sizeof(firmware_ver)-1)) { memcpy(name,p,sizeof(name)-1);
/* Firmware is incorrect */ name[sizeof(name)-1]=0;
tuner_info("Error: firmware is not for tm5600/6000 + Xcv2028/3028!\n"); p+=sizeof(name)-1;
rc=-EINVAL;
goto err;
}
p+=sizeof(firmware_ver)-1;
while(p<endp) { priv->version = le16_to_cpu(*(__u16 *)p);
if ((*p) & 0x80) { p += 2;
tuner_info("firmware: %s, ver %d.%d\n", name,
priv->version>>8, priv->version&0xff);
if (p+2>endp)
goto corrupt;
n_array = le16_to_cpu(*(__u16 *)p);
p += 2;
tuner_info("there are %d firmwares at %s\n", n_array, priv->ctrl.fname);
priv->firm=kzalloc(sizeof(*priv->firm)*n_array,GFP_KERNEL);
if (!fw) {
tuner_info("Not enough memory for loading firmware.\n");
rc=-ENOMEM;
goto done;
}
priv->firm_size = n_array;
n=-1;
while (p<endp) {
__u32 type, size;
v4l2_std_id id;
n++;
if (n >= n_array) {
tuner_info("Too much firmwares at the file\n");
goto corrupt;
}
/* Checks if there's enough bytes to read */
if (p+sizeof(type)+sizeof(id)+sizeof(size)>endp) {
tuner_info("Lost firmware!\n");
goto corrupt;
}
type = le32_to_cpu(*(__u32 *)p);
p += sizeof(type);
id = le64_to_cpu(*(v4l2_std_id *)p);
p += sizeof(id);
size = le32_to_cpu(*(v4l2_std_id *)p);
p += sizeof(size);
if ((!size)||(size+p>endp)) {
tuner_info("Firmware type %x, id %lx corrupt\n",
type, (unsigned long) id);
goto corrupt;
}
priv->firm[n].ptr=kzalloc(size,GFP_KERNEL);
if (!priv->firm[n].ptr) {
tuner_info("Not enough memory.\n");
rc=-ENOMEM;
goto err;
}
tuner_info("Loading firmware type %x, id %lx, size=%d.\n",
type, (unsigned long) id, size);
memcpy(priv->firm[n].ptr, p, size);
priv->firm[n].type = type;
priv->firm[n].id = id;
priv->firm[n].size = size;
p += size;
}
if (n+1 != priv->firm_size) {
tuner_info("Firmware file is incomplete!\n");
goto corrupt;
}
goto done;
corrupt:
rc=-EINVAL;
tuner_info("Error: firmware file is corrupted!\n");
err:
tuner_info("Releasing loaded firmware file.\n");
free_firmware(priv);
done:
release_firmware(fw);
tuner_info("Firmware files loaded.\n");
return rc;
}
static int load_firmware (struct dvb_frontend *fe, unsigned int type,
v4l2_std_id *id)
{
struct xc2028_data *priv = fe->tuner_priv;
int i, rc;
unsigned char *p, *endp, buf[priv->max_len];
tuner_info("%s called\n", __FUNCTION__);
if (!priv->firm) {
printk (KERN_ERR PREFIX "Error! firmware not loaded\n");
return -EINVAL;
}
if ((type == 0) && (*id == 0))
*id=V4L2_STD_PAL;
/* Seek for exact match */
for (i=0;i<priv->firm_size;i++) {
if ( (type == priv->firm[i].type) &&
(*id == priv->firm[i].id))
goto found;
}
/* Seek for generic video standard match */
for (i=0;i<priv->firm_size;i++) {
if ( (type == priv->firm[i].type) && (*id & priv->firm[i].id))
goto found;
}
/*FIXME: Would make sense to seek for type "hint" match ? */
tuner_info ("Can't find firmware for type=%x, id=%lx\n", type,
(long int)*id);
return -EINVAL;
found:
*id = priv->firm[i].id;
tuner_info ("Found firmware for type=%x, id=%lx\n", type,
(long int)*id);
p = priv->firm[i].ptr;
if (!p) {
printk(KERN_ERR PREFIX "Firmware pointer were freed!");
return -EINVAL;
}
endp = p+priv->firm[i].size;
while (p<endp) {
__u16 size;
/* Checks if there's enough bytes to read */
if (p+sizeof(size)>endp) {
tuner_info("missing bytes\n");
return -EINVAL;
}
size = le16_to_cpu(*(__u16 *)p);
p += sizeof(size);
if (size == 0xffff)
return 0;
if (!size) {
/* Special callback command received */ /* Special callback command received */
rc = priv->tuner_callback(priv->video_dev, rc = priv->tuner_callback(priv->video_dev,
XC2028_TUNER_RESET, (*p)&0x7f); XC2028_TUNER_RESET, 0);
if (rc<0) { if (rc<0) {
tuner_info("Error at RESET code %d\n", tuner_info("Error at RESET code %d\n",
(*p)&0x7f); (*p)&0x7f);
goto err; return -EINVAL;
} }
p++;
continue; continue;
} }
len=*p;
p++; /* Checks for a sleep command */
if (p+len+1>endp) { if (size & 0x8000) {
/* Firmware is incorrect */ msleep (size & 0x7fff);
tuner_info("Error: firmware is truncated!\n"); continue;
rc=-EINVAL;
goto err;
}
if (len<=0) {
tuner_info("Error: firmware file is corrupted!\n");
rc=-EINVAL;
goto err;
} }
i2c_send(rc, priv, p, len); if ((size + p > endp)) {
if (rc<0) tuner_info("missing bytes: need %d, have %d\n",
goto err; size, (int)(endp-p));
p+=len; return -EINVAL;
}
if (*p) buf[0] = *p;
msleep(*p);
p++; p++;
size--;
/* Sends message chunks */
while (size>0) {
int len = (size<priv->max_len-1)?size:priv->max_len-1;
memcpy(buf+1, p, len);
i2c_send(rc, priv, buf, len+1);
if (rc<0) {
tuner_info("%d returned from send\n",rc);
return -EINVAL;
}
p += len;
size -= len;
}
} }
return -EINVAL;
err:
release_firmware(fw);
return rc;
} }
static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode,
@ -196,11 +370,21 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode,
{ {
struct xc2028_data *priv = fe->tuner_priv; struct xc2028_data *priv = fe->tuner_priv;
int rc, version; int rc, version;
const char *name; v4l2_std_id std0=0;
int change_digital_bandwidth; unsigned int type0=0,type=0;
int change_digital_bandwidth;
tuner_info("%s called\n", __FUNCTION__); tuner_info("%s called\n", __FUNCTION__);
if (!priv->firm) {
if (!priv->ctrl.fname)
return -EINVAL;
rc=load_all_firmwares(fe);
if (rc<0)
return rc;
}
tuner_info( "I am in mode %u and I should switch to mode %i\n", tuner_info( "I am in mode %u and I should switch to mode %i\n",
priv->mode, new_mode); priv->mode, new_mode);
@ -213,23 +397,31 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode,
change_digital_bandwidth = (priv->mode == T_DIGITAL_TV change_digital_bandwidth = (priv->mode == T_DIGITAL_TV
&& bandwidth != priv->bandwidth) ? 1 : 0; && bandwidth != priv->bandwidth) ? 1 : 0;
tuner_info("old bandwidth %u, new bandwidth %u\n", priv->bandwidth, tuner_info("old bandwidth %u, new bandwidth %u\n", priv->bandwidth,
bandwidth); bandwidth);
if (priv->need_load_generic) { if (priv->need_load_generic) {
if (priv->bandwidth==8)
name = firmware_8MHZ_INIT0;
else
name = firmware_INIT0;
/* Reset is needed before loading firmware */ /* Reset is needed before loading firmware */
rc = priv->tuner_callback(priv->video_dev, rc = priv->tuner_callback(priv->video_dev,
XC2028_TUNER_RESET, 0); XC2028_TUNER_RESET, 0);
if (rc<0) if (rc<0)
return rc; return rc;
rc = load_firmware(fe,name); type0=BASE;
if (rc<0)
if (priv->ctrl.type == XC2028_FIRM_MTS)
type0 |= MTS;
if (priv->bandwidth==8)
type0 |= F8MHZ;
/* FIXME: How to load FM and FM|INPUT1 firmwares? */
rc = load_firmware(fe, type0, &std0);
if (rc<0) {
tuner_info("Error %d while loading generic firmware\n",
rc);
return rc; return rc;
}
priv->need_load_generic=0; priv->need_load_generic=0;
priv->firm_type=0; priv->firm_type=0;
@ -241,49 +433,53 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode,
tuner_info("I should change bandwidth %u\n", tuner_info("I should change bandwidth %u\n",
change_digital_bandwidth); change_digital_bandwidth);
/* FIXME: t->std makes no sense here */
if (change_digital_bandwidth) { if (change_digital_bandwidth) {
/*FIXME: Should allow selecting between D2620 and D2633 */
type |= D2620;
/* FIXME: When should select a DTV78 firmware?
*/
switch(bandwidth) { switch(bandwidth) {
case BANDWIDTH_8_MHZ: case BANDWIDTH_8_MHZ:
std = V4L2_STD_DTV_8MHZ; type |= DTV8;
break;
case BANDWIDTH_7_MHZ:
type |= DTV7;
break;
case BANDWIDTH_6_MHZ:
/* FIXME: Should allow select also ATSC */
type |= DTV6_QAM;
break; break;
case BANDWIDTH_7_MHZ: default:
std = V4L2_STD_DTV_7MHZ; tuner_info("error: bandwidth not supported.\n");
break;
case BANDWIDTH_6_MHZ:
std = V4L2_STD_DTV_6MHZ;
break;
default:
tuner_info("error: bandwidth not supported.\n");
}; };
priv->bandwidth = bandwidth; priv->bandwidth = bandwidth;
} }
/* Load INIT1, if needed */
tuner_info("Trying to load init1 firmware\n");
type0 = BASE | INIT1 | priv->ctrl.type;
if (priv->ctrl.type == XC2028_FIRM_MTS)
type0 |= MTS;
/* FIXME: Should handle errors - if INIT1 found */
rc = load_firmware(fe, type0, &std0);
/* FIXME: Should add support for FM radio
*/
if (priv->ctrl.type == XC2028_FIRM_MTS)
type |= MTS;
tuner_info("firmware standard to load: %08lx\n",(unsigned long) std);
if (priv->firm_type & std) { if (priv->firm_type & std) {
tuner_info("xc3028: no need to load a std-specific firmware.\n"); tuner_info("no need to load a std-specific firmware.\n");
return 0; return 0;
} }
rc = load_firmware(fe,firmware_INIT1); rc = load_firmware(fe, type, &std);
if (std & V4L2_STD_MN)
name=firmware_MN;
else if (std & V4L2_STD_DTV_6MHZ)
name=firmware_6M;
else if (std & V4L2_STD_DTV_7MHZ)
name=firmware_7M;
else if (std & V4L2_STD_DTV_8MHZ)
name=firmware_8M;
else if (std & V4L2_STD_PAL_B)
name=firmware_B;
else
name=firmware_DK;
tuner_info("loading firmware named %s.\n", name);
rc = load_firmware(fe, name);
if (rc<0) if (rc<0)
return rc; return rc;
@ -341,11 +537,11 @@ static int generic_set_tv_freq(struct dvb_frontend *fe, u32 freq /* in Hz */,
tuner_info("%s called\n", __FUNCTION__); tuner_info("%s called\n", __FUNCTION__);
mutex_lock(&priv->lock);
/* HACK: It seems that specific firmware need to be reloaded /* HACK: It seems that specific firmware need to be reloaded
when freq is changed */ when freq is changed */
mutex_lock(&priv->lock);
priv->firm_type=0; priv->firm_type=0;
/* Reset GPIO 1 */ /* Reset GPIO 1 */
@ -365,7 +561,13 @@ static int generic_set_tv_freq(struct dvb_frontend *fe, u32 freq /* in Hz */,
div = (freq - offset + DIV/2)/DIV; div = (freq - offset + DIV/2)/DIV;
/* CMD= Set frequency */ /* CMD= Set frequency */
send_seq(priv, {0x00, 0x02, 0x00, 0x00});
if (priv->version<0x0202) {
send_seq(priv, {0x00, 0x02, 0x00, 0x00});
} else {
send_seq(priv, {0x80, 0x02, 0x00, 0x00});
}
rc = priv->tuner_callback(priv->video_dev, XC2028_RESET_CLK, 1); rc = priv->tuner_callback(priv->video_dev, XC2028_RESET_CLK, 1);
if (rc<0) if (rc<0)
goto ret; goto ret;
@ -436,8 +638,13 @@ static int xc2028_dvb_release(struct dvb_frontend *fe)
priv->count--; priv->count--;
if (!priv->count) if (!priv->count) {
if (priv->ctrl.fname)
kfree(priv->ctrl.fname);
free_firmware(priv);
kfree (priv); kfree (priv);
}
return 0; return 0;
} }
@ -453,6 +660,32 @@ static int xc2028_get_frequency(struct dvb_frontend *fe, u32 *frequency)
return 0; return 0;
} }
static int xc2028_set_config (struct dvb_frontend *fe, void *priv_cfg)
{
struct xc2028_data *priv = fe->tuner_priv;
struct xc2028_ctrl *p = priv_cfg;
tuner_info("%s called\n", __FUNCTION__);
priv->ctrl.type = p->type;
if (p->fname) {
if (priv->ctrl.fname)
kfree(priv->ctrl.fname);
priv->ctrl.fname = kmalloc(strlen(p->fname)+1, GFP_KERNEL);
if (!priv->ctrl.fname)
return -ENOMEM;
free_firmware(priv);
strcpy(priv->ctrl.fname, p->fname);
}
tuner_info("%s OK\n", __FUNCTION__);
return 0;
}
static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = { static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = {
.info = { .info = {
.name = "Xceive XC3028", .name = "Xceive XC3028",
@ -461,6 +694,7 @@ static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = {
.frequency_step = 50000, .frequency_step = 50000,
}, },
.set_config = xc2028_set_config,
.set_analog_params = xc2028_set_tv_freq, .set_analog_params = xc2028_set_tv_freq,
.release = xc2028_dvb_release, .release = xc2028_dvb_release,
.get_frequency = xc2028_get_frequency, .get_frequency = xc2028_get_frequency,
@ -513,6 +747,8 @@ int xc2028_attach(struct dvb_frontend *fe, struct i2c_adapter* i2c_adap,
priv->dev = dev; priv->dev = dev;
priv->video_dev = video_dev; priv->video_dev = video_dev;
priv->tuner_callback = tuner_callback; priv->tuner_callback = tuner_callback;
priv->max_len = 13;
mutex_init(&priv->lock); mutex_init(&priv->lock);

View File

@ -9,13 +9,22 @@
#include "dvb_frontend.h" #include "dvb_frontend.h"
#define XC2028_DEFAULT_FIRMWARE "xc3028-v27.fw"
enum xc2028_firm_type {
XC2028_FIRM_NORMAL,
XC2028_FIRM_MTS,
};
struct xc2028_ctrl {
enum xc2028_firm_type type;
char *fname;
};
/* xc2028 commands for callback */ /* xc2028 commands for callback */
#define XC2028_TUNER_RESET 0 #define XC2028_TUNER_RESET 0
#define XC2028_RESET_CLK 1 #define XC2028_RESET_CLK 1
struct dvb_frontend;
struct i2c_client;
#if defined(CONFIG_TUNER_XC2028) || (defined(CONFIG_TUNER_XC2028_MODULE) && defined(MODULE)) #if defined(CONFIG_TUNER_XC2028) || (defined(CONFIG_TUNER_XC2028_MODULE) && defined(MODULE))
int xc2028_attach(struct dvb_frontend *fe, struct i2c_adapter* i2c_adap, int xc2028_attach(struct dvb_frontend *fe, struct i2c_adapter* i2c_adap,
u8 i2c_addr, struct device *dev, void *video_dev, u8 i2c_addr, struct device *dev, void *video_dev,