mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-30 19:51:31 -04:00
Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6
* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6: (345 commits) V4L/DVB (13542): ir-keytable: Allow dynamic table change V4L/DVB (13541): atbm8830: replace 64-bit division and floating point usage V4L/DVB (13540): ir-common: Cleanup get key evdev code V4L/DVB (13539): ir-common: add __func__ for debug messages V4L/DVB (13538): ir-common: Use a dynamic keycode table V4L/DVB (13537): ir: Prepare the code for dynamic keycode table allocation V4L/DVB (13536): em28xx: Use the full RC5 code on HVR-950 Remote Controller V4L/DVB (13535): ir-common: Add a hauppauge new table with the complete RC5 code V4L/DVB (13534): ir-common: Remove some unused fields/structs V4L/DVB (13533): ir: use dynamic tables, instead of static ones V4L/DVB (13532): ir-common: Add infrastructure to use a dynamic keycode table V4L/DVB (13531): ir-common: rename the debug routine to allow exporting it V4L/DVB (13458): go7007: subdev conversion V4L/DVB (13457): s2250: subdev conversion V4L/DVB (13456): s2250: Change module structure V4L/DVB (13528): em28xx: add support for em2800 VC211A card em28xx: don't reduce scale to half size for em2800 em28xx: don't load audio modules when AC97 is mis-detected em28xx: em2800 chips support max width of 640 V4L/DVB (13523): dvb-bt8xx: fix compile warning ... Fix up trivial conflicts due to spelling fixes from the trivial tree in Documentation/video4linux/gspca.txt drivers/media/video/cx18/cx18-mailbox.h
This commit is contained in:
commit
3e74683137
291 changed files with 28013 additions and 11214 deletions
|
|
@ -1,6 +1,6 @@
|
|||
saa7146-objs := saa7146_i2c.o saa7146_core.o
|
||||
saa7146_vv-objs := saa7146_fops.o saa7146_video.o saa7146_hlp.o saa7146_vbi.o
|
||||
ir-common-objs := ir-functions.o ir-keymaps.o
|
||||
ir-common-objs := ir-functions.o ir-keymaps.o ir-keytable.o
|
||||
|
||||
obj-y += tuners/
|
||||
obj-$(CONFIG_VIDEO_SAA7146) += saa7146.o
|
||||
|
|
|
|||
|
|
@ -34,22 +34,19 @@ static int repeat = 1;
|
|||
module_param(repeat, int, 0444);
|
||||
MODULE_PARM_DESC(repeat,"auto-repeat for IR keys (default: on)");
|
||||
|
||||
static int debug; /* debug level (0,1,2) */
|
||||
module_param(debug, int, 0644);
|
||||
|
||||
#define dprintk(level, fmt, arg...) if (debug >= level) \
|
||||
printk(KERN_DEBUG fmt , ## arg)
|
||||
int media_ir_debug; /* media_ir_debug level (0,1,2) */
|
||||
module_param_named(debug, media_ir_debug, int, 0644);
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
static void ir_input_key_event(struct input_dev *dev, struct ir_input_state *ir)
|
||||
{
|
||||
if (KEY_RESERVED == ir->keycode) {
|
||||
printk(KERN_INFO "%s: unknown key: key=0x%02x raw=0x%02x down=%d\n",
|
||||
dev->name,ir->ir_key,ir->ir_raw,ir->keypressed);
|
||||
printk(KERN_INFO "%s: unknown key: key=0x%02x down=%d\n",
|
||||
dev->name, ir->ir_key, ir->keypressed);
|
||||
return;
|
||||
}
|
||||
dprintk(1,"%s: key event code=%d down=%d\n",
|
||||
IR_dprintk(1,"%s: key event code=%d down=%d\n",
|
||||
dev->name,ir->keycode,ir->keypressed);
|
||||
input_report_key(dev,ir->keycode,ir->keypressed);
|
||||
input_sync(dev);
|
||||
|
|
@ -57,39 +54,34 @@ static void ir_input_key_event(struct input_dev *dev, struct ir_input_state *ir)
|
|||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
void ir_input_init(struct input_dev *dev, struct ir_input_state *ir,
|
||||
int ir_input_init(struct input_dev *dev, struct ir_input_state *ir,
|
||||
int ir_type, struct ir_scancode_table *ir_codes)
|
||||
{
|
||||
int i;
|
||||
|
||||
ir->ir_type = ir_type;
|
||||
|
||||
memset(ir->ir_codes, 0, sizeof(ir->ir_codes));
|
||||
ir->keytable.size = ir_roundup_tablesize(ir_codes->size);
|
||||
ir->keytable.scan = kzalloc(ir->keytable.size *
|
||||
sizeof(struct ir_scancode), GFP_KERNEL);
|
||||
if (!ir->keytable.scan)
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* FIXME: This is a temporary workaround to use the new IR tables
|
||||
* with the old approach. Later patches will replace this to a
|
||||
* proper method
|
||||
*/
|
||||
IR_dprintk(1, "Allocated space for %d keycode entries (%zd bytes)\n",
|
||||
ir->keytable.size,
|
||||
ir->keytable.size * sizeof(ir->keytable.scan));
|
||||
|
||||
if (ir_codes)
|
||||
for (i = 0; i < ir_codes->size; i++)
|
||||
if (ir_codes->scan[i].scancode < IR_KEYTAB_SIZE)
|
||||
ir->ir_codes[ir_codes->scan[i].scancode] = ir_codes->scan[i].keycode;
|
||||
ir_copy_table(&ir->keytable, ir_codes);
|
||||
ir_set_keycode_table(dev, &ir->keytable);
|
||||
|
||||
dev->keycode = ir->ir_codes;
|
||||
dev->keycodesize = sizeof(IR_KEYTAB_TYPE);
|
||||
dev->keycodemax = IR_KEYTAB_SIZE;
|
||||
for (i = 0; i < IR_KEYTAB_SIZE; i++)
|
||||
set_bit(ir->ir_codes[i], dev->keybit);
|
||||
clear_bit(0, dev->keybit);
|
||||
|
||||
set_bit(EV_KEY, dev->evbit);
|
||||
if (repeat)
|
||||
set_bit(EV_REP, dev->evbit);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ir_input_init);
|
||||
|
||||
|
||||
void ir_input_nokey(struct input_dev *dev, struct ir_input_state *ir)
|
||||
{
|
||||
if (ir->keypressed) {
|
||||
|
|
@ -100,9 +92,9 @@ void ir_input_nokey(struct input_dev *dev, struct ir_input_state *ir)
|
|||
EXPORT_SYMBOL_GPL(ir_input_nokey);
|
||||
|
||||
void ir_input_keydown(struct input_dev *dev, struct ir_input_state *ir,
|
||||
u32 ir_key, u32 ir_raw)
|
||||
u32 ir_key)
|
||||
{
|
||||
u32 keycode = IR_KEYCODE(ir->ir_codes, ir_key);
|
||||
u32 keycode = ir_g_keycode_from_table(dev, ir_key);
|
||||
|
||||
if (ir->keypressed && ir->keycode != keycode) {
|
||||
ir->keypressed = 0;
|
||||
|
|
@ -110,7 +102,6 @@ void ir_input_keydown(struct input_dev *dev, struct ir_input_state *ir,
|
|||
}
|
||||
if (!ir->keypressed) {
|
||||
ir->ir_key = ir_key;
|
||||
ir->ir_raw = ir_raw;
|
||||
ir->keycode = keycode;
|
||||
ir->keypressed = 1;
|
||||
ir_input_key_event(dev,ir);
|
||||
|
|
@ -275,7 +266,7 @@ EXPORT_SYMBOL_GPL(ir_decode_biphase);
|
|||
* saa7134 */
|
||||
|
||||
/* decode raw bit pattern to RC5 code */
|
||||
static u32 ir_rc5_decode(unsigned int code)
|
||||
u32 ir_rc5_decode(unsigned int code)
|
||||
{
|
||||
unsigned int org_code = code;
|
||||
unsigned int pair;
|
||||
|
|
@ -295,15 +286,16 @@ static u32 ir_rc5_decode(unsigned int code)
|
|||
rc5 |= 1;
|
||||
break;
|
||||
case 3:
|
||||
dprintk(1, "ir-common: ir_rc5_decode(%x) bad code\n", org_code);
|
||||
IR_dprintk(1, "ir-common: ir_rc5_decode(%x) bad code\n", org_code);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
dprintk(1, "ir-common: code=%x, rc5=%x, start=%x, toggle=%x, address=%x, "
|
||||
IR_dprintk(1, "ir-common: code=%x, rc5=%x, start=%x, toggle=%x, address=%x, "
|
||||
"instr=%x\n", rc5, org_code, RC5_START(rc5),
|
||||
RC5_TOGGLE(rc5), RC5_ADDR(rc5), RC5_INSTR(rc5));
|
||||
return rc5;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ir_rc5_decode);
|
||||
|
||||
void ir_rc5_timer_end(unsigned long data)
|
||||
{
|
||||
|
|
@ -330,20 +322,20 @@ void ir_rc5_timer_end(unsigned long data)
|
|||
|
||||
/* Allow some timer jitter (RC5 is ~24ms anyway so this is ok) */
|
||||
if (gap < 28000) {
|
||||
dprintk(1, "ir-common: spurious timer_end\n");
|
||||
IR_dprintk(1, "ir-common: spurious timer_end\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ir->last_bit < 20) {
|
||||
/* ignore spurious codes (caused by light/other remotes) */
|
||||
dprintk(1, "ir-common: short code: %x\n", ir->code);
|
||||
IR_dprintk(1, "ir-common: short code: %x\n", ir->code);
|
||||
} else {
|
||||
ir->code = (ir->code << ir->shift_by) | 1;
|
||||
rc5 = ir_rc5_decode(ir->code);
|
||||
|
||||
/* two start bits? */
|
||||
if (RC5_START(rc5) != ir->start) {
|
||||
dprintk(1, "ir-common: rc5 start bits invalid: %u\n", RC5_START(rc5));
|
||||
IR_dprintk(1, "ir-common: rc5 start bits invalid: %u\n", RC5_START(rc5));
|
||||
|
||||
/* right address? */
|
||||
} else if (RC5_ADDR(rc5) == ir->addr) {
|
||||
|
|
@ -353,11 +345,10 @@ void ir_rc5_timer_end(unsigned long data)
|
|||
/* Good code, decide if repeat/repress */
|
||||
if (toggle != RC5_TOGGLE(ir->last_rc5) ||
|
||||
instr != RC5_INSTR(ir->last_rc5)) {
|
||||
dprintk(1, "ir-common: instruction %x, toggle %x\n", instr,
|
||||
IR_dprintk(1, "ir-common: instruction %x, toggle %x\n", instr,
|
||||
toggle);
|
||||
ir_input_nokey(ir->dev, &ir->ir);
|
||||
ir_input_keydown(ir->dev, &ir->ir, instr,
|
||||
instr);
|
||||
ir_input_keydown(ir->dev, &ir->ir, instr);
|
||||
}
|
||||
|
||||
/* Set/reset key-up timer */
|
||||
|
|
@ -376,7 +367,7 @@ void ir_rc5_timer_keyup(unsigned long data)
|
|||
{
|
||||
struct card_ir *ir = (struct card_ir *)data;
|
||||
|
||||
dprintk(1, "ir-common: key released\n");
|
||||
IR_dprintk(1, "ir-common: key released\n");
|
||||
ir_input_nokey(ir->dev, &ir->ir);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ir_rc5_timer_keyup);
|
||||
|
|
|
|||
|
|
@ -1705,6 +1705,7 @@ static struct ir_scancode ir_codes_winfast[] = {
|
|||
{ 0x37, KEY_RADIO }, /* FM */
|
||||
{ 0x38, KEY_DVD },
|
||||
|
||||
{ 0x1a, KEY_MODE}, /* change to MCE mode on Y04G0051 */
|
||||
{ 0x3e, KEY_F21 }, /* MCE +VOL, on Y04G0033 */
|
||||
{ 0x3a, KEY_F22 }, /* MCE -VOL, on Y04G0033 */
|
||||
{ 0x3b, KEY_F23 }, /* MCE +CH, on Y04G0033 */
|
||||
|
|
@ -1846,6 +1847,76 @@ struct ir_scancode_table ir_codes_hauppauge_new_table = {
|
|||
};
|
||||
EXPORT_SYMBOL_GPL(ir_codes_hauppauge_new_table);
|
||||
|
||||
/*
|
||||
* Hauppauge:the newer, gray remotes (seems there are multiple
|
||||
* slightly different versions), shipped with cx88+ivtv cards.
|
||||
*
|
||||
* This table contains the complete RC5 code, instead of just the data part
|
||||
*/
|
||||
static struct ir_scancode ir_codes_rc5_hauppauge_new[] = {
|
||||
/* Keys 0 to 9 */
|
||||
{ 0x1e00, KEY_0 },
|
||||
{ 0x1e01, KEY_1 },
|
||||
{ 0x1e02, KEY_2 },
|
||||
{ 0x1e03, KEY_3 },
|
||||
{ 0x1e04, KEY_4 },
|
||||
{ 0x1e05, KEY_5 },
|
||||
{ 0x1e06, KEY_6 },
|
||||
{ 0x1e07, KEY_7 },
|
||||
{ 0x1e08, KEY_8 },
|
||||
{ 0x1e09, KEY_9 },
|
||||
|
||||
{ 0x1e0a, KEY_TEXT }, /* keypad asterisk as well */
|
||||
{ 0x1e0b, KEY_RED }, /* red button */
|
||||
{ 0x1e0c, KEY_RADIO },
|
||||
{ 0x1e0d, KEY_MENU },
|
||||
{ 0x1e0e, KEY_SUBTITLE }, /* also the # key */
|
||||
{ 0x1e0f, KEY_MUTE },
|
||||
{ 0x1e10, KEY_VOLUMEUP },
|
||||
{ 0x1e11, KEY_VOLUMEDOWN },
|
||||
{ 0x1e12, KEY_PREVIOUS }, /* previous channel */
|
||||
{ 0x1e14, KEY_UP },
|
||||
{ 0x1e15, KEY_DOWN },
|
||||
{ 0x1e16, KEY_LEFT },
|
||||
{ 0x1e17, KEY_RIGHT },
|
||||
{ 0x1e18, KEY_VIDEO }, /* Videos */
|
||||
{ 0x1e19, KEY_AUDIO }, /* Music */
|
||||
/* 0x1e1a: Pictures - presume this means
|
||||
"Multimedia Home Platform" -
|
||||
no "PICTURES" key in input.h
|
||||
*/
|
||||
{ 0x1e1a, KEY_MHP },
|
||||
|
||||
{ 0x1e1b, KEY_EPG }, /* Guide */
|
||||
{ 0x1e1c, KEY_TV },
|
||||
{ 0x1e1e, KEY_NEXTSONG }, /* skip >| */
|
||||
{ 0x1e1f, KEY_EXIT }, /* back/exit */
|
||||
{ 0x1e20, KEY_CHANNELUP }, /* channel / program + */
|
||||
{ 0x1e21, KEY_CHANNELDOWN }, /* channel / program - */
|
||||
{ 0x1e22, KEY_CHANNEL }, /* source (old black remote) */
|
||||
{ 0x1e24, KEY_PREVIOUSSONG }, /* replay |< */
|
||||
{ 0x1e25, KEY_ENTER }, /* OK */
|
||||
{ 0x1e26, KEY_SLEEP }, /* minimize (old black remote) */
|
||||
{ 0x1e29, KEY_BLUE }, /* blue key */
|
||||
{ 0x1e2e, KEY_GREEN }, /* green button */
|
||||
{ 0x1e30, KEY_PAUSE }, /* pause */
|
||||
{ 0x1e32, KEY_REWIND }, /* backward << */
|
||||
{ 0x1e34, KEY_FASTFORWARD }, /* forward >> */
|
||||
{ 0x1e35, KEY_PLAY },
|
||||
{ 0x1e36, KEY_STOP },
|
||||
{ 0x1e37, KEY_RECORD }, /* recording */
|
||||
{ 0x1e38, KEY_YELLOW }, /* yellow key */
|
||||
{ 0x1e3b, KEY_SELECT }, /* top right button */
|
||||
{ 0x1e3c, KEY_ZOOM }, /* full */
|
||||
{ 0x1e3d, KEY_POWER }, /* system power (green button) */
|
||||
};
|
||||
|
||||
struct ir_scancode_table ir_codes_rc5_hauppauge_new_table = {
|
||||
.scan = ir_codes_rc5_hauppauge_new,
|
||||
.size = ARRAY_SIZE(ir_codes_rc5_hauppauge_new),
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(ir_codes_rc5_hauppauge_new_table);
|
||||
|
||||
static struct ir_scancode ir_codes_npgtech[] = {
|
||||
{ 0x1d, KEY_SWITCHVIDEOMODE }, /* switch inputs */
|
||||
{ 0x2a, KEY_FRONT },
|
||||
|
|
@ -2964,6 +3035,101 @@ struct ir_scancode_table ir_codes_dm1105_nec_table = {
|
|||
};
|
||||
EXPORT_SYMBOL_GPL(ir_codes_dm1105_nec_table);
|
||||
|
||||
static struct ir_scancode ir_codes_tevii_nec[] = {
|
||||
{ 0x0a, KEY_POWER2},
|
||||
{ 0x0c, KEY_MUTE},
|
||||
{ 0x11, KEY_1},
|
||||
{ 0x12, KEY_2},
|
||||
{ 0x13, KEY_3},
|
||||
{ 0x14, KEY_4},
|
||||
{ 0x15, KEY_5},
|
||||
{ 0x16, KEY_6},
|
||||
{ 0x17, KEY_7},
|
||||
{ 0x18, KEY_8},
|
||||
{ 0x19, KEY_9},
|
||||
{ 0x10, KEY_0},
|
||||
{ 0x1c, KEY_MENU},
|
||||
{ 0x0f, KEY_VOLUMEDOWN},
|
||||
{ 0x1a, KEY_LAST},
|
||||
{ 0x0e, KEY_OPEN},
|
||||
{ 0x04, KEY_RECORD},
|
||||
{ 0x09, KEY_VOLUMEUP},
|
||||
{ 0x08, KEY_CHANNELUP},
|
||||
{ 0x07, KEY_PVR},
|
||||
{ 0x0b, KEY_TIME},
|
||||
{ 0x02, KEY_RIGHT},
|
||||
{ 0x03, KEY_LEFT},
|
||||
{ 0x00, KEY_UP},
|
||||
{ 0x1f, KEY_OK},
|
||||
{ 0x01, KEY_DOWN},
|
||||
{ 0x05, KEY_TUNER},
|
||||
{ 0x06, KEY_CHANNELDOWN},
|
||||
{ 0x40, KEY_PLAYPAUSE},
|
||||
{ 0x1e, KEY_REWIND},
|
||||
{ 0x1b, KEY_FAVORITES},
|
||||
{ 0x1d, KEY_BACK},
|
||||
{ 0x4d, KEY_FASTFORWARD},
|
||||
{ 0x44, KEY_EPG},
|
||||
{ 0x4c, KEY_INFO},
|
||||
{ 0x41, KEY_AB},
|
||||
{ 0x43, KEY_AUDIO},
|
||||
{ 0x45, KEY_SUBTITLE},
|
||||
{ 0x4a, KEY_LIST},
|
||||
{ 0x46, KEY_F1},
|
||||
{ 0x47, KEY_F2},
|
||||
{ 0x5e, KEY_F3},
|
||||
{ 0x5c, KEY_F4},
|
||||
{ 0x52, KEY_F5},
|
||||
{ 0x5a, KEY_F6},
|
||||
{ 0x56, KEY_MODE},
|
||||
{ 0x58, KEY_SWITCHVIDEOMODE},
|
||||
};
|
||||
struct ir_scancode_table ir_codes_tevii_nec_table = {
|
||||
.scan = ir_codes_tevii_nec,
|
||||
.size = ARRAY_SIZE(ir_codes_tevii_nec),
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(ir_codes_tevii_nec_table);
|
||||
|
||||
static struct ir_scancode ir_codes_tbs_nec[] = {
|
||||
{ 0x04, KEY_POWER2}, /*power*/
|
||||
{ 0x14, KEY_MUTE}, /*mute*/
|
||||
{ 0x07, KEY_1},
|
||||
{ 0x06, KEY_2},
|
||||
{ 0x05, KEY_3},
|
||||
{ 0x0b, KEY_4},
|
||||
{ 0x0a, KEY_5},
|
||||
{ 0x09, KEY_6},
|
||||
{ 0x0f, KEY_7},
|
||||
{ 0x0e, KEY_8},
|
||||
{ 0x0d, KEY_9},
|
||||
{ 0x12, KEY_0},
|
||||
{ 0x16, KEY_CHANNELUP}, /*ch+*/
|
||||
{ 0x11, KEY_CHANNELDOWN},/*ch-*/
|
||||
{ 0x13, KEY_VOLUMEUP}, /*vol+*/
|
||||
{ 0x0c, KEY_VOLUMEDOWN},/*vol-*/
|
||||
{ 0x03, KEY_RECORD}, /*rec*/
|
||||
{ 0x18, KEY_PAUSE}, /*pause*/
|
||||
{ 0x19, KEY_OK}, /*ok*/
|
||||
{ 0x1a, KEY_CAMERA}, /* snapshot */
|
||||
{ 0x01, KEY_UP},
|
||||
{ 0x10, KEY_LEFT},
|
||||
{ 0x02, KEY_RIGHT},
|
||||
{ 0x08, KEY_DOWN},
|
||||
{ 0x15, KEY_FAVORITES},
|
||||
{ 0x17, KEY_SUBTITLE},
|
||||
{ 0x1d, KEY_ZOOM},
|
||||
{ 0x1f, KEY_EXIT},
|
||||
{ 0x1e, KEY_MENU},
|
||||
{ 0x1c, KEY_EPG},
|
||||
{ 0x00, KEY_PREVIOUS},
|
||||
{ 0x1b, KEY_MODE},
|
||||
};
|
||||
struct ir_scancode_table ir_codes_tbs_nec_table = {
|
||||
.scan = ir_codes_tbs_nec,
|
||||
.size = ARRAY_SIZE(ir_codes_tbs_nec),
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(ir_codes_tbs_nec_table);
|
||||
|
||||
/* Terratec Cinergy Hybrid T USB XS
|
||||
Devin Heitmueller <dheitmueller@linuxtv.org>
|
||||
*/
|
||||
|
|
@ -3147,3 +3313,4 @@ struct ir_scancode_table ir_codes_gadmei_rm008z_table = {
|
|||
.size = ARRAY_SIZE(ir_codes_gadmei_rm008z),
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(ir_codes_gadmei_rm008z_table);
|
||||
|
||||
|
|
|
|||
429
drivers/media/common/ir-keytable.c
Normal file
429
drivers/media/common/ir-keytable.c
Normal file
|
|
@ -0,0 +1,429 @@
|
|||
/* ir-register.c - handle IR scancode->keycode tables
|
||||
*
|
||||
* Copyright (C) 2009 by Mauro Carvalho Chehab <mchehab@redhat.com>
|
||||
*/
|
||||
|
||||
#include <linux/usb/input.h>
|
||||
|
||||
#include <media/ir-common.h>
|
||||
|
||||
#define IR_TAB_MIN_SIZE 32
|
||||
#define IR_TAB_MAX_SIZE 1024
|
||||
|
||||
/**
|
||||
* ir_seek_table() - returns the element order on the table
|
||||
* @rc_tab: the ir_scancode_table with the keymap to be used
|
||||
* @scancode: the scancode that we're seeking
|
||||
*
|
||||
* This routine is used by the input routines when a key is pressed at the
|
||||
* IR. The scancode is received and needs to be converted into a keycode.
|
||||
* If the key is not found, it returns KEY_UNKNOWN. Otherwise, returns the
|
||||
* corresponding keycode from the table.
|
||||
*/
|
||||
static int ir_seek_table(struct ir_scancode_table *rc_tab, u32 scancode)
|
||||
{
|
||||
int rc;
|
||||
unsigned long flags;
|
||||
struct ir_scancode *keymap = rc_tab->scan;
|
||||
|
||||
spin_lock_irqsave(&rc_tab->lock, flags);
|
||||
|
||||
/* FIXME: replace it by a binary search */
|
||||
|
||||
for (rc = 0; rc < rc_tab->size; rc++)
|
||||
if (keymap[rc].scancode == scancode)
|
||||
goto exit;
|
||||
|
||||
/* Not found */
|
||||
rc = -EINVAL;
|
||||
|
||||
exit:
|
||||
spin_unlock_irqrestore(&rc_tab->lock, flags);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* ir_roundup_tablesize() - gets an optimum value for the table size
|
||||
* @n_elems: minimum number of entries to store keycodes
|
||||
*
|
||||
* This routine is used to choose the keycode table size.
|
||||
*
|
||||
* In order to have some empty space for new keycodes,
|
||||
* and knowing in advance that kmalloc allocates only power of two
|
||||
* segments, it optimizes the allocated space to have some spare space
|
||||
* for those new keycodes by using the maximum number of entries that
|
||||
* will be effectively be allocated by kmalloc.
|
||||
* In order to reduce the quantity of table resizes, it has a minimum
|
||||
* table size of IR_TAB_MIN_SIZE.
|
||||
*/
|
||||
int ir_roundup_tablesize(int n_elems)
|
||||
{
|
||||
size_t size;
|
||||
|
||||
if (n_elems < IR_TAB_MIN_SIZE)
|
||||
n_elems = IR_TAB_MIN_SIZE;
|
||||
|
||||
/*
|
||||
* As kmalloc only allocates sizes of power of two, get as
|
||||
* much entries as possible for the allocated memory segment
|
||||
*/
|
||||
size = roundup_pow_of_two(n_elems * sizeof(struct ir_scancode));
|
||||
n_elems = size / sizeof(struct ir_scancode);
|
||||
|
||||
return n_elems;
|
||||
}
|
||||
|
||||
/**
|
||||
* ir_copy_table() - copies a keytable, discarding the unused entries
|
||||
* @destin: destin table
|
||||
* @origin: origin table
|
||||
*
|
||||
* Copies all entries where the keycode is not KEY_UNKNOWN/KEY_RESERVED
|
||||
*/
|
||||
|
||||
int ir_copy_table(struct ir_scancode_table *destin,
|
||||
const struct ir_scancode_table *origin)
|
||||
{
|
||||
int i, j = 0;
|
||||
|
||||
for (i = 0; i < origin->size; i++) {
|
||||
if (origin->scan[i].keycode == KEY_UNKNOWN ||
|
||||
origin->scan[i].keycode == KEY_RESERVED)
|
||||
continue;
|
||||
|
||||
memcpy(&destin->scan[j], &origin->scan[i], sizeof(struct ir_scancode));
|
||||
j++;
|
||||
}
|
||||
destin->size = j;
|
||||
|
||||
IR_dprintk(1, "Copied %d scancodes to the new keycode table\n", destin->size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ir_getkeycode() - get a keycode at the evdev scancode ->keycode table
|
||||
* @dev: the struct input_dev device descriptor
|
||||
* @scancode: the desired scancode
|
||||
* @keycode: the keycode to be retorned.
|
||||
*
|
||||
* This routine is used to handle evdev EVIOCGKEY ioctl.
|
||||
* If the key is not found, returns -EINVAL, otherwise, returns 0.
|
||||
*/
|
||||
static int ir_getkeycode(struct input_dev *dev,
|
||||
int scancode, int *keycode)
|
||||
{
|
||||
int elem;
|
||||
struct ir_scancode_table *rc_tab = input_get_drvdata(dev);
|
||||
|
||||
elem = ir_seek_table(rc_tab, scancode);
|
||||
if (elem >= 0) {
|
||||
*keycode = rc_tab->scan[elem].keycode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Scancode not found and table can't be expanded
|
||||
*/
|
||||
if (elem < 0 && rc_tab->size == IR_TAB_MAX_SIZE)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* If is there extra space, returns KEY_RESERVED,
|
||||
* otherwise, input core won't let ir_setkeycode to work
|
||||
*/
|
||||
*keycode = KEY_RESERVED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ir_is_resize_needed() - Check if the table needs rezise
|
||||
* @table: keycode table that may need to resize
|
||||
* @n_elems: minimum number of entries to store keycodes
|
||||
*
|
||||
* Considering that kmalloc uses power of two storage areas, this
|
||||
* routine detects if the real alloced size will change. If not, it
|
||||
* just returns without doing nothing. Otherwise, it will extend or
|
||||
* reduce the table size to meet the new needs.
|
||||
*
|
||||
* It returns 0 if no resize is needed, 1 otherwise.
|
||||
*/
|
||||
static int ir_is_resize_needed(struct ir_scancode_table *table, int n_elems)
|
||||
{
|
||||
int cur_size = ir_roundup_tablesize(table->size);
|
||||
int new_size = ir_roundup_tablesize(n_elems);
|
||||
|
||||
if (cur_size == new_size)
|
||||
return 0;
|
||||
|
||||
/* Resize is needed */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* ir_delete_key() - remove a keycode from the table
|
||||
* @rc_tab: keycode table
|
||||
* @elem: element to be removed
|
||||
*
|
||||
*/
|
||||
static void ir_delete_key(struct ir_scancode_table *rc_tab, int elem)
|
||||
{
|
||||
unsigned long flags = 0;
|
||||
int newsize = rc_tab->size - 1;
|
||||
int resize = ir_is_resize_needed(rc_tab, newsize);
|
||||
struct ir_scancode *oldkeymap = rc_tab->scan;
|
||||
struct ir_scancode *newkeymap;
|
||||
|
||||
if (resize) {
|
||||
newkeymap = kzalloc(ir_roundup_tablesize(newsize) *
|
||||
sizeof(*newkeymap), GFP_ATOMIC);
|
||||
|
||||
/* There's no memory for resize. Keep the old table */
|
||||
if (!newkeymap)
|
||||
resize = 0;
|
||||
}
|
||||
|
||||
if (!resize) {
|
||||
newkeymap = oldkeymap;
|
||||
|
||||
/* We'll modify the live table. Lock it */
|
||||
spin_lock_irqsave(&rc_tab->lock, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy the elements before the one that will be deleted
|
||||
* if (!resize), both oldkeymap and newkeymap points
|
||||
* to the same place, so, there's no need to copy
|
||||
*/
|
||||
if (resize && elem > 0)
|
||||
memcpy(newkeymap, oldkeymap,
|
||||
elem * sizeof(*newkeymap));
|
||||
|
||||
/*
|
||||
* Copy the other elements overwriting the element to be removed
|
||||
* This operation applies to both resize and non-resize case
|
||||
*/
|
||||
if (elem < newsize)
|
||||
memcpy(&newkeymap[elem], &oldkeymap[elem + 1],
|
||||
(newsize - elem) * sizeof(*newkeymap));
|
||||
|
||||
if (resize) {
|
||||
/*
|
||||
* As the copy happened to a temporary table, only here
|
||||
* it needs to lock while replacing the table pointers
|
||||
* to use the new table
|
||||
*/
|
||||
spin_lock_irqsave(&rc_tab->lock, flags);
|
||||
rc_tab->size = newsize;
|
||||
rc_tab->scan = newkeymap;
|
||||
spin_unlock_irqrestore(&rc_tab->lock, flags);
|
||||
|
||||
/* Frees the old keytable */
|
||||
kfree(oldkeymap);
|
||||
} else {
|
||||
rc_tab->size = newsize;
|
||||
spin_unlock_irqrestore(&rc_tab->lock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ir_insert_key() - insert a keycode at the table
|
||||
* @rc_tab: keycode table
|
||||
* @scancode: the desired scancode
|
||||
* @keycode: the keycode to be retorned.
|
||||
*
|
||||
*/
|
||||
static int ir_insert_key(struct ir_scancode_table *rc_tab,
|
||||
int scancode, int keycode)
|
||||
{
|
||||
unsigned long flags;
|
||||
int elem = rc_tab->size;
|
||||
int newsize = rc_tab->size + 1;
|
||||
int resize = ir_is_resize_needed(rc_tab, newsize);
|
||||
struct ir_scancode *oldkeymap = rc_tab->scan;
|
||||
struct ir_scancode *newkeymap;
|
||||
|
||||
if (resize) {
|
||||
newkeymap = kzalloc(ir_roundup_tablesize(newsize) *
|
||||
sizeof(*newkeymap), GFP_ATOMIC);
|
||||
if (!newkeymap)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(newkeymap, oldkeymap,
|
||||
rc_tab->size * sizeof(*newkeymap));
|
||||
} else
|
||||
newkeymap = oldkeymap;
|
||||
|
||||
/* Stores the new code at the table */
|
||||
IR_dprintk(1, "#%d: New scan 0x%04x with key 0x%04x\n",
|
||||
rc_tab->size, scancode, keycode);
|
||||
|
||||
spin_lock_irqsave(&rc_tab->lock, flags);
|
||||
rc_tab->size = newsize;
|
||||
if (resize) {
|
||||
rc_tab->scan = newkeymap;
|
||||
kfree(oldkeymap);
|
||||
}
|
||||
newkeymap[elem].scancode = scancode;
|
||||
newkeymap[elem].keycode = keycode;
|
||||
spin_unlock_irqrestore(&rc_tab->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ir_setkeycode() - set a keycode at the evdev scancode ->keycode table
|
||||
* @dev: the struct input_dev device descriptor
|
||||
* @scancode: the desired scancode
|
||||
* @keycode: the keycode to be retorned.
|
||||
*
|
||||
* This routine is used to handle evdev EVIOCSKEY ioctl.
|
||||
* There's one caveat here: how can we increase the size of the table?
|
||||
* If the key is not found, returns -EINVAL, otherwise, returns 0.
|
||||
*/
|
||||
static int ir_setkeycode(struct input_dev *dev,
|
||||
int scancode, int keycode)
|
||||
{
|
||||
int rc = 0;
|
||||
struct ir_scancode_table *rc_tab = input_get_drvdata(dev);
|
||||
struct ir_scancode *keymap = rc_tab->scan;
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* Handle keycode table deletions
|
||||
*
|
||||
* If userspace is adding a KEY_UNKNOWN or KEY_RESERVED,
|
||||
* deal as a trial to remove an existing scancode attribution
|
||||
* if table become too big, reduce it to save space
|
||||
*/
|
||||
if (keycode == KEY_UNKNOWN || keycode == KEY_RESERVED) {
|
||||
rc = ir_seek_table(rc_tab, scancode);
|
||||
if (rc < 0)
|
||||
return 0;
|
||||
|
||||
IR_dprintk(1, "#%d: Deleting scan 0x%04x\n", rc, scancode);
|
||||
clear_bit(keymap[rc].keycode, dev->keybit);
|
||||
ir_delete_key(rc_tab, rc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle keycode replacements
|
||||
*
|
||||
* If the scancode exists, just replace by the new value
|
||||
*/
|
||||
rc = ir_seek_table(rc_tab, scancode);
|
||||
if (rc >= 0) {
|
||||
IR_dprintk(1, "#%d: Replacing scan 0x%04x with key 0x%04x\n",
|
||||
rc, scancode, keycode);
|
||||
|
||||
clear_bit(keymap[rc].keycode, dev->keybit);
|
||||
|
||||
spin_lock_irqsave(&rc_tab->lock, flags);
|
||||
keymap[rc].keycode = keycode;
|
||||
spin_unlock_irqrestore(&rc_tab->lock, flags);
|
||||
|
||||
set_bit(keycode, dev->keybit);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle new scancode inserts
|
||||
*
|
||||
* reallocate table if needed and insert a new keycode
|
||||
*/
|
||||
|
||||
/* Avoid growing the table indefinitely */
|
||||
if (rc_tab->size + 1 > IR_TAB_MAX_SIZE)
|
||||
return -EINVAL;
|
||||
|
||||
rc = ir_insert_key(rc_tab, scancode, keycode);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
set_bit(keycode, dev->keybit);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ir_g_keycode_from_table() - gets the keycode that corresponds to a scancode
|
||||
* @input_dev: the struct input_dev descriptor of the device
|
||||
* @scancode: the scancode that we're seeking
|
||||
*
|
||||
* This routine is used by the input routines when a key is pressed at the
|
||||
* IR. The scancode is received and needs to be converted into a keycode.
|
||||
* If the key is not found, it returns KEY_UNKNOWN. Otherwise, returns the
|
||||
* corresponding keycode from the table.
|
||||
*/
|
||||
u32 ir_g_keycode_from_table(struct input_dev *dev, u32 scancode)
|
||||
{
|
||||
struct ir_scancode_table *rc_tab = input_get_drvdata(dev);
|
||||
struct ir_scancode *keymap = rc_tab->scan;
|
||||
int elem;
|
||||
|
||||
elem = ir_seek_table(rc_tab, scancode);
|
||||
if (elem >= 0) {
|
||||
IR_dprintk(1, "%s: scancode 0x%04x keycode 0x%02x\n",
|
||||
dev->name, scancode, keymap[elem].keycode);
|
||||
|
||||
return rc_tab->scan[elem].keycode;
|
||||
}
|
||||
|
||||
printk(KERN_INFO "%s: unknown key for scancode 0x%04x\n",
|
||||
dev->name, scancode);
|
||||
|
||||
/* Reports userspace that an unknown keycode were got */
|
||||
return KEY_RESERVED;
|
||||
}
|
||||
|
||||
/**
|
||||
* ir_set_keycode_table() - sets the IR keycode table and add the handlers
|
||||
* for keymap table get/set
|
||||
* @input_dev: the struct input_dev descriptor of the device
|
||||
* @rc_tab: the struct ir_scancode_table table of scancode/keymap
|
||||
*
|
||||
* This routine is used to initialize the input infrastructure to work with
|
||||
* an IR.
|
||||
* It should be called before registering the IR device.
|
||||
*/
|
||||
int ir_set_keycode_table(struct input_dev *input_dev,
|
||||
struct ir_scancode_table *rc_tab)
|
||||
{
|
||||
struct ir_scancode *keymap = rc_tab->scan;
|
||||
int i;
|
||||
|
||||
spin_lock_init(&rc_tab->lock);
|
||||
|
||||
if (rc_tab->scan == NULL || !rc_tab->size)
|
||||
return -EINVAL;
|
||||
|
||||
/* set the bits for the keys */
|
||||
IR_dprintk(1, "key map size: %d\n", rc_tab->size);
|
||||
for (i = 0; i < rc_tab->size; i++) {
|
||||
IR_dprintk(1, "#%d: setting bit for keycode 0x%04x\n",
|
||||
i, keymap[i].keycode);
|
||||
set_bit(keymap[i].keycode, input_dev->keybit);
|
||||
}
|
||||
|
||||
input_dev->getkeycode = ir_getkeycode;
|
||||
input_dev->setkeycode = ir_setkeycode;
|
||||
input_set_drvdata(input_dev, rc_tab);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ir_input_free(struct input_dev *dev)
|
||||
{
|
||||
struct ir_scancode_table *rc_tab = input_get_drvdata(dev);
|
||||
|
||||
IR_dprintk(1, "Freed keycode table\n");
|
||||
|
||||
rc_tab->size = 0;
|
||||
kfree(rc_tab->scan);
|
||||
rc_tab->scan = NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ir_input_free);
|
||||
|
||||
|
|
@ -1205,6 +1205,13 @@ static int buffer_activate (struct saa7146_dev *dev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void release_all_pagetables(struct saa7146_dev *dev, struct saa7146_buf *buf)
|
||||
{
|
||||
saa7146_pgtable_free(dev->pci, &buf->pt[0]);
|
||||
saa7146_pgtable_free(dev->pci, &buf->pt[1]);
|
||||
saa7146_pgtable_free(dev->pci, &buf->pt[2]);
|
||||
}
|
||||
|
||||
static int buffer_prepare(struct videobuf_queue *q,
|
||||
struct videobuf_buffer *vb, enum v4l2_field field)
|
||||
{
|
||||
|
|
@ -1257,16 +1264,12 @@ static int buffer_prepare(struct videobuf_queue *q,
|
|||
|
||||
sfmt = format_by_fourcc(dev,buf->fmt->pixelformat);
|
||||
|
||||
release_all_pagetables(dev, buf);
|
||||
if( 0 != IS_PLANAR(sfmt->trans)) {
|
||||
saa7146_pgtable_free(dev->pci, &buf->pt[0]);
|
||||
saa7146_pgtable_free(dev->pci, &buf->pt[1]);
|
||||
saa7146_pgtable_free(dev->pci, &buf->pt[2]);
|
||||
|
||||
saa7146_pgtable_alloc(dev->pci, &buf->pt[0]);
|
||||
saa7146_pgtable_alloc(dev->pci, &buf->pt[1]);
|
||||
saa7146_pgtable_alloc(dev->pci, &buf->pt[2]);
|
||||
} else {
|
||||
saa7146_pgtable_free(dev->pci, &buf->pt[0]);
|
||||
saa7146_pgtable_alloc(dev->pci, &buf->pt[0]);
|
||||
}
|
||||
|
||||
|
|
@ -1329,6 +1332,9 @@ static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
|
|||
struct saa7146_buf *buf = (struct saa7146_buf *)vb;
|
||||
|
||||
DEB_CAP(("vbuf:%p\n",vb));
|
||||
|
||||
release_all_pagetables(dev, buf);
|
||||
|
||||
saa7146_dma_free(dev,q,buf);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -172,4 +172,11 @@ config MEDIA_TUNER_MC44S803
|
|||
help
|
||||
Say Y here to support the Freescale MC44S803 based tuners
|
||||
|
||||
config MEDIA_TUNER_MAX2165
|
||||
tristate "Maxim MAX2165 silicon tuner"
|
||||
depends on VIDEO_MEDIA && I2C
|
||||
default m if MEDIA_TUNER_CUSTOMISE
|
||||
help
|
||||
A driver for the silicon tuner MAX2165 from Maxim.
|
||||
|
||||
endif # MEDIA_TUNER_CUSTOMISE
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ obj-$(CONFIG_MEDIA_TUNER_MT2131) += mt2131.o
|
|||
obj-$(CONFIG_MEDIA_TUNER_MXL5005S) += mxl5005s.o
|
||||
obj-$(CONFIG_MEDIA_TUNER_MXL5007T) += mxl5007t.o
|
||||
obj-$(CONFIG_MEDIA_TUNER_MC44S803) += mc44s803.o
|
||||
obj-$(CONFIG_MEDIA_TUNER_MAX2165) += max2165.o
|
||||
|
||||
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
|
||||
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
|
||||
|
|
|
|||
442
drivers/media/common/tuners/max2165.c
Normal file
442
drivers/media/common/tuners/max2165.c
Normal file
|
|
@ -0,0 +1,442 @@
|
|||
/*
|
||||
* Driver for Maxim MAX2165 silicon tuner
|
||||
*
|
||||
* Copyright (c) 2009 David T. L. Wong <davidtlwong@gmail.com>
|
||||
*
|
||||
* 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/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/videodev2.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/dvb/frontend.h>
|
||||
#include <linux/i2c.h>
|
||||
|
||||
#include "dvb_frontend.h"
|
||||
|
||||
#include "max2165.h"
|
||||
#include "max2165_priv.h"
|
||||
#include "tuner-i2c.h"
|
||||
|
||||
#define dprintk(args...) \
|
||||
do { \
|
||||
if (debug) \
|
||||
printk(KERN_DEBUG "max2165: " args); \
|
||||
} while (0)
|
||||
|
||||
static int debug;
|
||||
module_param(debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
|
||||
|
||||
static int max2165_write_reg(struct max2165_priv *priv, u8 reg, u8 data)
|
||||
{
|
||||
int ret;
|
||||
u8 buf[] = { reg, data };
|
||||
struct i2c_msg msg = { .flags = 0, .buf = buf, .len = 2 };
|
||||
|
||||
msg.addr = priv->config->i2c_address;
|
||||
|
||||
if (debug >= 2)
|
||||
printk(KERN_DEBUG "%s: reg=0x%02X, data=0x%02X\n",
|
||||
__func__, reg, data);
|
||||
|
||||
ret = i2c_transfer(priv->i2c, &msg, 1);
|
||||
|
||||
if (ret != 1)
|
||||
dprintk(KERN_DEBUG "%s: error reg=0x%x, data=0x%x, ret=%i\n",
|
||||
__func__, reg, data, ret);
|
||||
|
||||
return (ret != 1) ? -EIO : 0;
|
||||
}
|
||||
|
||||
static int max2165_read_reg(struct max2165_priv *priv, u8 reg, u8 *p_data)
|
||||
{
|
||||
int ret;
|
||||
u8 dev_addr = priv->config->i2c_address;
|
||||
|
||||
u8 b0[] = { reg };
|
||||
u8 b1[] = { 0 };
|
||||
struct i2c_msg msg[] = {
|
||||
{ .addr = dev_addr, .flags = 0, .buf = b0, .len = 1 },
|
||||
{ .addr = dev_addr, .flags = I2C_M_RD, .buf = b1, .len = 1 },
|
||||
};
|
||||
|
||||
ret = i2c_transfer(priv->i2c, msg, 2);
|
||||
if (ret != 2) {
|
||||
dprintk(KERN_DEBUG "%s: error reg=0x%x, ret=%i\n",
|
||||
__func__, reg, ret);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
*p_data = b1[0];
|
||||
if (debug >= 2)
|
||||
printk(KERN_DEBUG "%s: reg=0x%02X, data=0x%02X\n",
|
||||
__func__, reg, b1[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max2165_mask_write_reg(struct max2165_priv *priv, u8 reg,
|
||||
u8 mask, u8 data)
|
||||
{
|
||||
int ret;
|
||||
u8 v;
|
||||
|
||||
data &= mask;
|
||||
ret = max2165_read_reg(priv, reg, &v);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
v &= ~mask;
|
||||
v |= data;
|
||||
ret = max2165_write_reg(priv, reg, v);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int max2165_read_rom_table(struct max2165_priv *priv)
|
||||
{
|
||||
u8 dat[3];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
max2165_write_reg(priv, REG_ROM_TABLE_ADDR, i + 1);
|
||||
max2165_read_reg(priv, REG_ROM_TABLE_DATA, &dat[i]);
|
||||
}
|
||||
|
||||
priv->tf_ntch_low_cfg = dat[0] >> 4;
|
||||
priv->tf_ntch_hi_cfg = dat[0] & 0x0F;
|
||||
priv->tf_balun_low_ref = dat[1] & 0x0F;
|
||||
priv->tf_balun_hi_ref = dat[1] >> 4;
|
||||
priv->bb_filter_7mhz_cfg = dat[2] & 0x0F;
|
||||
priv->bb_filter_8mhz_cfg = dat[2] >> 4;
|
||||
|
||||
dprintk("tf_ntch_low_cfg = 0x%X\n", priv->tf_ntch_low_cfg);
|
||||
dprintk("tf_ntch_hi_cfg = 0x%X\n", priv->tf_ntch_hi_cfg);
|
||||
dprintk("tf_balun_low_ref = 0x%X\n", priv->tf_balun_low_ref);
|
||||
dprintk("tf_balun_hi_ref = 0x%X\n", priv->tf_balun_hi_ref);
|
||||
dprintk("bb_filter_7mhz_cfg = 0x%X\n", priv->bb_filter_7mhz_cfg);
|
||||
dprintk("bb_filter_8mhz_cfg = 0x%X\n", priv->bb_filter_8mhz_cfg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max2165_set_osc(struct max2165_priv *priv, u8 osc /*MHz*/)
|
||||
{
|
||||
u8 v;
|
||||
|
||||
v = (osc / 2);
|
||||
if (v == 2)
|
||||
v = 0x7;
|
||||
else
|
||||
v -= 8;
|
||||
|
||||
max2165_mask_write_reg(priv, REG_PLL_CFG, 0x07, v);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max2165_set_bandwidth(struct max2165_priv *priv, u32 bw)
|
||||
{
|
||||
u8 val;
|
||||
|
||||
if (bw == BANDWIDTH_8_MHZ)
|
||||
val = priv->bb_filter_8mhz_cfg;
|
||||
else
|
||||
val = priv->bb_filter_7mhz_cfg;
|
||||
|
||||
max2165_mask_write_reg(priv, REG_BASEBAND_CTRL, 0xF0, val << 4);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fixpt_div32(u32 dividend, u32 divisor, u32 *quotient, u32 *fraction)
|
||||
{
|
||||
u32 remainder;
|
||||
u32 q, f = 0;
|
||||
int i;
|
||||
|
||||
if (0 == divisor)
|
||||
return -1;
|
||||
|
||||
q = dividend / divisor;
|
||||
remainder = dividend - q * divisor;
|
||||
|
||||
for (i = 0; i < 31; i++) {
|
||||
remainder <<= 1;
|
||||
if (remainder >= divisor) {
|
||||
f += 1;
|
||||
remainder -= divisor;
|
||||
}
|
||||
f <<= 1;
|
||||
}
|
||||
|
||||
*quotient = q;
|
||||
*fraction = f;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max2165_set_rf(struct max2165_priv *priv, u32 freq)
|
||||
{
|
||||
u8 tf;
|
||||
u8 tf_ntch;
|
||||
double t;
|
||||
u32 quotient, fraction;
|
||||
|
||||
/* Set PLL divider according to RF frequency */
|
||||
fixpt_div32(freq / 1000, priv->config->osc_clk * 1000,
|
||||
"ient, &fraction);
|
||||
|
||||
/* 20-bit fraction */
|
||||
fraction >>= 12;
|
||||
|
||||
max2165_write_reg(priv, REG_NDIV_INT, quotient);
|
||||
max2165_mask_write_reg(priv, REG_NDIV_FRAC2, 0x0F, fraction >> 16);
|
||||
max2165_write_reg(priv, REG_NDIV_FRAC1, fraction >> 8);
|
||||
max2165_write_reg(priv, REG_NDIV_FRAC0, fraction);
|
||||
|
||||
/* Norch Filter */
|
||||
tf_ntch = (freq < 725000000) ?
|
||||
priv->tf_ntch_low_cfg : priv->tf_ntch_hi_cfg;
|
||||
|
||||
/* Tracking filter balun */
|
||||
t = priv->tf_balun_low_ref;
|
||||
t += (priv->tf_balun_hi_ref - priv->tf_balun_low_ref)
|
||||
* (freq / 1000 - 470000) / (780000 - 470000);
|
||||
|
||||
tf = t;
|
||||
dprintk("tf = %X\n", tf);
|
||||
tf |= tf_ntch << 4;
|
||||
|
||||
max2165_write_reg(priv, REG_TRACK_FILTER, tf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void max2165_debug_status(struct max2165_priv *priv)
|
||||
{
|
||||
u8 status, autotune;
|
||||
u8 auto_vco_success, auto_vco_active;
|
||||
u8 pll_locked;
|
||||
u8 dc_offset_low, dc_offset_hi;
|
||||
u8 signal_lv_over_threshold;
|
||||
u8 vco, vco_sub_band, adc;
|
||||
|
||||
max2165_read_reg(priv, REG_STATUS, &status);
|
||||
max2165_read_reg(priv, REG_AUTOTUNE, &autotune);
|
||||
|
||||
auto_vco_success = (status >> 6) & 0x01;
|
||||
auto_vco_active = (status >> 5) & 0x01;
|
||||
pll_locked = (status >> 4) & 0x01;
|
||||
dc_offset_low = (status >> 3) & 0x01;
|
||||
dc_offset_hi = (status >> 2) & 0x01;
|
||||
signal_lv_over_threshold = status & 0x01;
|
||||
|
||||
vco = autotune >> 6;
|
||||
vco_sub_band = (autotune >> 3) & 0x7;
|
||||
adc = autotune & 0x7;
|
||||
|
||||
dprintk("auto VCO active: %d, auto VCO success: %d\n",
|
||||
auto_vco_active, auto_vco_success);
|
||||
dprintk("PLL locked: %d\n", pll_locked);
|
||||
dprintk("DC offset low: %d, DC offset high: %d\n",
|
||||
dc_offset_low, dc_offset_hi);
|
||||
dprintk("Signal lvl over threshold: %d\n", signal_lv_over_threshold);
|
||||
dprintk("VCO: %d, VCO Sub-band: %d, ADC: %d\n", vco, vco_sub_band, adc);
|
||||
}
|
||||
|
||||
static int max2165_set_params(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_parameters *params)
|
||||
{
|
||||
struct max2165_priv *priv = fe->tuner_priv;
|
||||
int ret;
|
||||
|
||||
dprintk("%s() frequency=%d (Hz)\n", __func__, params->frequency);
|
||||
if (fe->ops.info.type == FE_ATSC) {
|
||||
return -EINVAL;
|
||||
} else if (fe->ops.info.type == FE_OFDM) {
|
||||
dprintk("%s() OFDM\n", __func__);
|
||||
switch (params->u.ofdm.bandwidth) {
|
||||
case BANDWIDTH_6_MHZ:
|
||||
return -EINVAL;
|
||||
case BANDWIDTH_7_MHZ:
|
||||
case BANDWIDTH_8_MHZ:
|
||||
priv->frequency = params->frequency;
|
||||
priv->bandwidth = params->u.ofdm.bandwidth;
|
||||
break;
|
||||
default:
|
||||
printk(KERN_ERR "MAX2165 bandwidth not set!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
printk(KERN_ERR "MAX2165 modulation type not supported!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dprintk("%s() frequency=%d\n", __func__, priv->frequency);
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
max2165_set_bandwidth(priv, priv->bandwidth);
|
||||
ret = max2165_set_rf(priv, priv->frequency);
|
||||
mdelay(50);
|
||||
max2165_debug_status(priv);
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 0);
|
||||
|
||||
if (ret != 0)
|
||||
return -EREMOTEIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max2165_get_frequency(struct dvb_frontend *fe, u32 *freq)
|
||||
{
|
||||
struct max2165_priv *priv = fe->tuner_priv;
|
||||
dprintk("%s()\n", __func__);
|
||||
*freq = priv->frequency;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max2165_get_bandwidth(struct dvb_frontend *fe, u32 *bw)
|
||||
{
|
||||
struct max2165_priv *priv = fe->tuner_priv;
|
||||
dprintk("%s()\n", __func__);
|
||||
|
||||
*bw = priv->bandwidth;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max2165_get_status(struct dvb_frontend *fe, u32 *status)
|
||||
{
|
||||
struct max2165_priv *priv = fe->tuner_priv;
|
||||
u16 lock_status = 0;
|
||||
|
||||
dprintk("%s()\n", __func__);
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
|
||||
max2165_debug_status(priv);
|
||||
*status = lock_status;
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max2165_sleep(struct dvb_frontend *fe)
|
||||
{
|
||||
dprintk("%s()\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max2165_init(struct dvb_frontend *fe)
|
||||
{
|
||||
struct max2165_priv *priv = fe->tuner_priv;
|
||||
dprintk("%s()\n", __func__);
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
|
||||
/* Setup initial values */
|
||||
/* Fractional Mode on */
|
||||
max2165_write_reg(priv, REG_NDIV_FRAC2, 0x18);
|
||||
/* LNA on */
|
||||
max2165_write_reg(priv, REG_LNA, 0x01);
|
||||
max2165_write_reg(priv, REG_PLL_CFG, 0x7A);
|
||||
max2165_write_reg(priv, REG_TEST, 0x08);
|
||||
max2165_write_reg(priv, REG_SHUTDOWN, 0x40);
|
||||
max2165_write_reg(priv, REG_VCO_CTRL, 0x84);
|
||||
max2165_write_reg(priv, REG_BASEBAND_CTRL, 0xC3);
|
||||
max2165_write_reg(priv, REG_DC_OFFSET_CTRL, 0x75);
|
||||
max2165_write_reg(priv, REG_DC_OFFSET_DAC, 0x00);
|
||||
max2165_write_reg(priv, REG_ROM_TABLE_ADDR, 0x00);
|
||||
|
||||
max2165_set_osc(priv, priv->config->osc_clk);
|
||||
|
||||
max2165_read_rom_table(priv);
|
||||
|
||||
max2165_set_bandwidth(priv, BANDWIDTH_8_MHZ);
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max2165_release(struct dvb_frontend *fe)
|
||||
{
|
||||
struct max2165_priv *priv = fe->tuner_priv;
|
||||
dprintk("%s()\n", __func__);
|
||||
|
||||
kfree(priv);
|
||||
fe->tuner_priv = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dvb_tuner_ops max2165_tuner_ops = {
|
||||
.info = {
|
||||
.name = "Maxim MAX2165",
|
||||
.frequency_min = 470000000,
|
||||
.frequency_max = 780000000,
|
||||
.frequency_step = 50000,
|
||||
},
|
||||
|
||||
.release = max2165_release,
|
||||
.init = max2165_init,
|
||||
.sleep = max2165_sleep,
|
||||
|
||||
.set_params = max2165_set_params,
|
||||
.set_analog_params = NULL,
|
||||
.get_frequency = max2165_get_frequency,
|
||||
.get_bandwidth = max2165_get_bandwidth,
|
||||
.get_status = max2165_get_status
|
||||
};
|
||||
|
||||
struct dvb_frontend *max2165_attach(struct dvb_frontend *fe,
|
||||
struct i2c_adapter *i2c,
|
||||
struct max2165_config *cfg)
|
||||
{
|
||||
struct max2165_priv *priv = NULL;
|
||||
|
||||
dprintk("%s(%d-%04x)\n", __func__,
|
||||
i2c ? i2c_adapter_id(i2c) : -1,
|
||||
cfg ? cfg->i2c_address : -1);
|
||||
|
||||
priv = kzalloc(sizeof(struct max2165_priv), GFP_KERNEL);
|
||||
if (priv == NULL)
|
||||
return NULL;
|
||||
|
||||
memcpy(&fe->ops.tuner_ops, &max2165_tuner_ops,
|
||||
sizeof(struct dvb_tuner_ops));
|
||||
|
||||
priv->config = cfg;
|
||||
priv->i2c = i2c;
|
||||
fe->tuner_priv = priv;
|
||||
|
||||
max2165_init(fe);
|
||||
max2165_debug_status(priv);
|
||||
|
||||
return fe;
|
||||
}
|
||||
EXPORT_SYMBOL(max2165_attach);
|
||||
|
||||
MODULE_AUTHOR("David T. L. Wong <[email protected]>");
|
||||
MODULE_DESCRIPTION("Maxim MAX2165 silicon tuner driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
48
drivers/media/common/tuners/max2165.h
Normal file
48
drivers/media/common/tuners/max2165.h
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Driver for Maxim MAX2165 silicon tuner
|
||||
*
|
||||
* Copyright (c) 2009 David T. L. Wong <davidtlwong@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __MAX2165_H__
|
||||
#define __MAX2165_H__
|
||||
|
||||
struct dvb_frontend;
|
||||
struct i2c_adapter;
|
||||
|
||||
struct max2165_config {
|
||||
u8 i2c_address;
|
||||
u8 osc_clk; /* in MHz, selectable values: 4,16,18,20,22,24,26,28 */
|
||||
};
|
||||
|
||||
#if defined(CONFIG_MEDIA_TUNER_MAX2165) || \
|
||||
(defined(CONFIG_MEDIA_TUNER_MAX2165_MODULE) && defined(MODULE))
|
||||
extern struct dvb_frontend *max2165_attach(struct dvb_frontend *fe,
|
||||
struct i2c_adapter *i2c,
|
||||
struct max2165_config *cfg);
|
||||
#else
|
||||
static inline struct dvb_frontend *max2165_attach(struct dvb_frontend *fe,
|
||||
struct i2c_adapter *i2c,
|
||||
struct max2165_config *cfg)
|
||||
{
|
||||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
60
drivers/media/common/tuners/max2165_priv.h
Normal file
60
drivers/media/common/tuners/max2165_priv.h
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Driver for Maxim MAX2165 silicon tuner
|
||||
*
|
||||
* Copyright (c) 2009 David T. L. Wong <davidtlwong@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __MAX2165_PRIV_H__
|
||||
#define __MAX2165_PRIV_H__
|
||||
|
||||
#define REG_NDIV_INT 0x00
|
||||
#define REG_NDIV_FRAC2 0x01
|
||||
#define REG_NDIV_FRAC1 0x02
|
||||
#define REG_NDIV_FRAC0 0x03
|
||||
#define REG_TRACK_FILTER 0x04
|
||||
#define REG_LNA 0x05
|
||||
#define REG_PLL_CFG 0x06
|
||||
#define REG_TEST 0x07
|
||||
#define REG_SHUTDOWN 0x08
|
||||
#define REG_VCO_CTRL 0x09
|
||||
#define REG_BASEBAND_CTRL 0x0A
|
||||
#define REG_DC_OFFSET_CTRL 0x0B
|
||||
#define REG_DC_OFFSET_DAC 0x0C
|
||||
#define REG_ROM_TABLE_ADDR 0x0D
|
||||
|
||||
/* Read Only Registers */
|
||||
#define REG_ROM_TABLE_DATA 0x10
|
||||
#define REG_STATUS 0x11
|
||||
#define REG_AUTOTUNE 0x12
|
||||
|
||||
struct max2165_priv {
|
||||
struct max2165_config *config;
|
||||
struct i2c_adapter *i2c;
|
||||
|
||||
u32 frequency;
|
||||
u32 bandwidth;
|
||||
|
||||
u8 tf_ntch_low_cfg;
|
||||
u8 tf_ntch_hi_cfg;
|
||||
u8 tf_balun_low_ref;
|
||||
u8 tf_balun_hi_ref;
|
||||
u8 bb_filter_7mhz_cfg;
|
||||
u8 bb_filter_8mhz_cfg;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -2789,7 +2789,10 @@ static u16 MXL_TuneRF(struct dvb_frontend *fe, u32 RF_Freq)
|
|||
|
||||
/* add for 2.6.5 Special setting for QAM */
|
||||
if (state->Mod_Type == MXL_QAM) {
|
||||
if (state->RF_IN < 680000000)
|
||||
if (state->config->qam_gain != 0)
|
||||
status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN,
|
||||
state->config->qam_gain);
|
||||
else if (state->RF_IN < 680000000)
|
||||
status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 3);
|
||||
else
|
||||
status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 2);
|
||||
|
|
|
|||
|
|
@ -108,6 +108,10 @@ struct mxl5005s_config {
|
|||
#define MXL_LOW_IF 1
|
||||
u8 if_mode;
|
||||
|
||||
/* Some boards need to override the built-in logic for determining
|
||||
the gain when in QAM mode (the HVR-1600 is one such case) */
|
||||
u8 qam_gain;
|
||||
|
||||
/* Stuff I don't know what to do with */
|
||||
u8 AgcMasterByte;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -196,7 +196,7 @@ static void copy_reg_bits(struct reg_pair_t *reg_pair1,
|
|||
i = j = 0;
|
||||
|
||||
while (reg_pair1[i].reg || reg_pair1[i].val) {
|
||||
while (reg_pair2[j].reg || reg_pair2[j].reg) {
|
||||
while (reg_pair2[j].reg || reg_pair2[j].val) {
|
||||
if (reg_pair1[i].reg != reg_pair2[j].reg) {
|
||||
j++;
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -326,12 +326,24 @@ int tda18271_init_regs(struct dvb_frontend *fe)
|
|||
regs[R_EB22] = 0x48;
|
||||
regs[R_EB23] = 0xb0;
|
||||
|
||||
if (priv->small_i2c) {
|
||||
switch (priv->small_i2c) {
|
||||
case TDA18271_08_BYTE_CHUNK_INIT:
|
||||
tda18271_write_regs(fe, 0x00, 0x08);
|
||||
tda18271_write_regs(fe, 0x08, 0x08);
|
||||
tda18271_write_regs(fe, 0x10, 0x08);
|
||||
tda18271_write_regs(fe, 0x18, 0x08);
|
||||
tda18271_write_regs(fe, 0x20, 0x07);
|
||||
break;
|
||||
case TDA18271_16_BYTE_CHUNK_INIT:
|
||||
tda18271_write_regs(fe, 0x00, 0x10);
|
||||
tda18271_write_regs(fe, 0x10, 0x10);
|
||||
tda18271_write_regs(fe, 0x20, 0x07);
|
||||
} else
|
||||
break;
|
||||
case TDA18271_39_BYTE_CHUNK_INIT:
|
||||
default:
|
||||
tda18271_write_regs(fe, 0x00, TDA18271_NUM_REGS);
|
||||
break;
|
||||
}
|
||||
|
||||
/* setup agc1 gain */
|
||||
regs[R_EB17] = 0x00;
|
||||
|
|
|
|||
|
|
@ -256,8 +256,9 @@ static int tda18271c2_rf_tracking_filters_correction(struct dvb_frontend *fe,
|
|||
struct tda18271_priv *priv = fe->tuner_priv;
|
||||
struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state;
|
||||
unsigned char *regs = priv->tda18271_regs;
|
||||
int tm_current, rfcal_comp, approx, i, ret;
|
||||
u8 dc_over_dt, rf_tab;
|
||||
int i, ret;
|
||||
u8 tm_current, dc_over_dt, rf_tab;
|
||||
s32 rfcal_comp, approx;
|
||||
|
||||
/* power up */
|
||||
ret = tda18271_set_standby_mode(fe, 0, 0, 0);
|
||||
|
|
@ -277,11 +278,11 @@ static int tda18271c2_rf_tracking_filters_correction(struct dvb_frontend *fe,
|
|||
return i;
|
||||
|
||||
if ((0 == map[i].rf3) || (freq / 1000 < map[i].rf2)) {
|
||||
approx = map[i].rf_a1 *
|
||||
(freq / 1000 - map[i].rf1) + map[i].rf_b1 + rf_tab;
|
||||
approx = map[i].rf_a1 * (s32)(freq / 1000 - map[i].rf1) +
|
||||
map[i].rf_b1 + rf_tab;
|
||||
} else {
|
||||
approx = map[i].rf_a2 *
|
||||
(freq / 1000 - map[i].rf2) + map[i].rf_b2 + rf_tab;
|
||||
approx = map[i].rf_a2 * (s32)(freq / 1000 - map[i].rf2) +
|
||||
map[i].rf_b2 + rf_tab;
|
||||
}
|
||||
|
||||
if (approx < 0)
|
||||
|
|
@ -292,9 +293,9 @@ static int tda18271c2_rf_tracking_filters_correction(struct dvb_frontend *fe,
|
|||
tda18271_lookup_map(fe, RF_CAL_DC_OVER_DT, &freq, &dc_over_dt);
|
||||
|
||||
/* calculate temperature compensation */
|
||||
rfcal_comp = dc_over_dt * (tm_current - priv->tm_rfcal) / 1000;
|
||||
rfcal_comp = dc_over_dt * (s32)(tm_current - priv->tm_rfcal) / 1000;
|
||||
|
||||
regs[R_EB14] = approx + rfcal_comp;
|
||||
regs[R_EB14] = (unsigned char)(approx + rfcal_comp);
|
||||
ret = tda18271_write_regs(fe, R_EB14, 1);
|
||||
fail:
|
||||
return ret;
|
||||
|
|
@ -572,6 +573,7 @@ static int tda18271_rf_tracking_filters_init(struct dvb_frontend *fe, u32 freq)
|
|||
struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state;
|
||||
unsigned char *regs = priv->tda18271_regs;
|
||||
int bcal, rf, i;
|
||||
s32 divisor, dividend;
|
||||
#define RF1 0
|
||||
#define RF2 1
|
||||
#define RF3 2
|
||||
|
|
@ -610,20 +612,22 @@ static int tda18271_rf_tracking_filters_init(struct dvb_frontend *fe, u32 freq)
|
|||
switch (rf) {
|
||||
case RF1:
|
||||
map[i].rf_a1 = 0;
|
||||
map[i].rf_b1 = prog_cal[RF1] - prog_tab[RF1];
|
||||
map[i].rf_b1 = (s32)(prog_cal[RF1] - prog_tab[RF1]);
|
||||
map[i].rf1 = rf_freq[RF1] / 1000;
|
||||
break;
|
||||
case RF2:
|
||||
map[i].rf_a1 = (prog_cal[RF2] - prog_tab[RF2] -
|
||||
prog_cal[RF1] + prog_tab[RF1]) /
|
||||
(s32)((rf_freq[RF2] - rf_freq[RF1]) / 1000);
|
||||
dividend = (s32)(prog_cal[RF2] - prog_tab[RF2]) -
|
||||
(s32)(prog_cal[RF1] + prog_tab[RF1]);
|
||||
divisor = (s32)(rf_freq[RF2] - rf_freq[RF1]) / 1000;
|
||||
map[i].rf_a1 = (dividend / divisor);
|
||||
map[i].rf2 = rf_freq[RF2] / 1000;
|
||||
break;
|
||||
case RF3:
|
||||
map[i].rf_a2 = (prog_cal[RF3] - prog_tab[RF3] -
|
||||
prog_cal[RF2] + prog_tab[RF2]) /
|
||||
(s32)((rf_freq[RF3] - rf_freq[RF2]) / 1000);
|
||||
map[i].rf_b2 = prog_cal[RF2] - prog_tab[RF2];
|
||||
dividend = (s32)(prog_cal[RF3] - prog_tab[RF3]) -
|
||||
(s32)(prog_cal[RF2] + prog_tab[RF2]);
|
||||
divisor = (s32)(rf_freq[RF3] - rf_freq[RF2]) / 1000;
|
||||
map[i].rf_a2 = (dividend / divisor);
|
||||
map[i].rf_b2 = (s32)(prog_cal[RF2] - prog_tab[RF2]);
|
||||
map[i].rf3 = rf_freq[RF3] / 1000;
|
||||
break;
|
||||
default:
|
||||
|
|
@ -1181,6 +1185,48 @@ static int tda18271_get_id(struct dvb_frontend *fe)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int tda18271_setup_configuration(struct dvb_frontend *fe,
|
||||
struct tda18271_config *cfg)
|
||||
{
|
||||
struct tda18271_priv *priv = fe->tuner_priv;
|
||||
|
||||
priv->gate = (cfg) ? cfg->gate : TDA18271_GATE_AUTO;
|
||||
priv->role = (cfg) ? cfg->role : TDA18271_MASTER;
|
||||
priv->config = (cfg) ? cfg->config : 0;
|
||||
priv->small_i2c = (cfg) ?
|
||||
cfg->small_i2c : TDA18271_39_BYTE_CHUNK_INIT;
|
||||
priv->output_opt = (cfg) ?
|
||||
cfg->output_opt : TDA18271_OUTPUT_LT_XT_ON;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int tda18271_need_cal_on_startup(struct tda18271_config *cfg)
|
||||
{
|
||||
/* tda18271_cal_on_startup == -1 when cal module option is unset */
|
||||
return ((tda18271_cal_on_startup == -1) ?
|
||||
/* honor configuration setting */
|
||||
((cfg) && (cfg->rf_cal_on_startup)) :
|
||||
/* module option overrides configuration setting */
|
||||
(tda18271_cal_on_startup)) ? 1 : 0;
|
||||
}
|
||||
|
||||
static int tda18271_set_config(struct dvb_frontend *fe, void *priv_cfg)
|
||||
{
|
||||
struct tda18271_config *cfg = (struct tda18271_config *) priv_cfg;
|
||||
|
||||
tda18271_setup_configuration(fe, cfg);
|
||||
|
||||
if (tda18271_need_cal_on_startup(cfg))
|
||||
tda18271_init(fe);
|
||||
|
||||
/* override default std map with values in config struct */
|
||||
if ((cfg) && (cfg->std_map))
|
||||
tda18271_update_std_map(fe, cfg->std_map);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dvb_tuner_ops tda18271_tuner_ops = {
|
||||
.info = {
|
||||
.name = "NXP TDA18271HD",
|
||||
|
|
@ -1193,6 +1239,7 @@ static struct dvb_tuner_ops tda18271_tuner_ops = {
|
|||
.set_params = tda18271_set_params,
|
||||
.set_analog_params = tda18271_set_analog_params,
|
||||
.release = tda18271_release,
|
||||
.set_config = tda18271_set_config,
|
||||
.get_frequency = tda18271_get_frequency,
|
||||
.get_bandwidth = tda18271_get_bandwidth,
|
||||
};
|
||||
|
|
@ -1213,33 +1260,14 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr,
|
|||
case 0:
|
||||
goto fail;
|
||||
case 1:
|
||||
{
|
||||
/* new tuner instance */
|
||||
int rf_cal_on_startup;
|
||||
fe->tuner_priv = priv;
|
||||
|
||||
priv->gate = (cfg) ? cfg->gate : TDA18271_GATE_AUTO;
|
||||
priv->role = (cfg) ? cfg->role : TDA18271_MASTER;
|
||||
priv->config = (cfg) ? cfg->config : 0;
|
||||
priv->small_i2c = (cfg) ? cfg->small_i2c : 0;
|
||||
priv->output_opt = (cfg) ?
|
||||
cfg->output_opt : TDA18271_OUTPUT_LT_XT_ON;
|
||||
|
||||
/* tda18271_cal_on_startup == -1 when cal
|
||||
* module option is unset */
|
||||
if (tda18271_cal_on_startup == -1) {
|
||||
/* honor attach-time configuration */
|
||||
rf_cal_on_startup =
|
||||
((cfg) && (cfg->rf_cal_on_startup)) ? 1 : 0;
|
||||
} else {
|
||||
/* module option overrides attach configuration */
|
||||
rf_cal_on_startup = tda18271_cal_on_startup;
|
||||
}
|
||||
tda18271_setup_configuration(fe, cfg);
|
||||
|
||||
priv->cal_initialized = false;
|
||||
mutex_init(&priv->lock);
|
||||
|
||||
fe->tuner_priv = priv;
|
||||
|
||||
if (tda_fail(tda18271_get_id(fe)))
|
||||
goto fail;
|
||||
|
||||
|
|
@ -1249,12 +1277,12 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr,
|
|||
mutex_lock(&priv->lock);
|
||||
tda18271_init_regs(fe);
|
||||
|
||||
if ((rf_cal_on_startup) && (priv->id == TDA18271HDC2))
|
||||
if ((tda18271_need_cal_on_startup(cfg)) &&
|
||||
(priv->id == TDA18271HDC2))
|
||||
tda18271c2_rf_cal_init(fe);
|
||||
|
||||
mutex_unlock(&priv->lock);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
/* existing tuner instance */
|
||||
fe->tuner_priv = priv;
|
||||
|
|
@ -1271,7 +1299,11 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr,
|
|||
priv->small_i2c = cfg->small_i2c;
|
||||
if (cfg->output_opt)
|
||||
priv->output_opt = cfg->output_opt;
|
||||
if (cfg->std_map)
|
||||
tda18271_update_std_map(fe, cfg->std_map);
|
||||
}
|
||||
if (tda18271_need_cal_on_startup(cfg))
|
||||
tda18271_init(fe);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -1298,7 +1330,7 @@ EXPORT_SYMBOL_GPL(tda18271_attach);
|
|||
MODULE_DESCRIPTION("NXP TDA18271HD analog / digital tuner driver");
|
||||
MODULE_AUTHOR("Michael Krufky <[email protected]>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION("0.3");
|
||||
MODULE_VERSION("0.4");
|
||||
|
||||
/*
|
||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
||||
|
|
|
|||
|
|
@ -978,6 +978,7 @@ static struct tda18271_cid_target_map tda18271_cid_target[] = {
|
|||
int tda18271_lookup_cid_target(struct dvb_frontend *fe,
|
||||
u32 *freq, u8 *cid_target, u16 *count_limit)
|
||||
{
|
||||
struct tda18271_priv *priv = fe->tuner_priv;
|
||||
int i = 0;
|
||||
|
||||
while ((tda18271_cid_target[i].rfmax * 1000) < *freq) {
|
||||
|
|
|
|||
|
|
@ -80,10 +80,10 @@ struct tda18271_rf_tracking_filter_cal {
|
|||
u32 rf1;
|
||||
u32 rf2;
|
||||
u32 rf3;
|
||||
int rf_a1;
|
||||
int rf_b1;
|
||||
int rf_a2;
|
||||
int rf_b2;
|
||||
s32 rf_a1;
|
||||
s32 rf_b1;
|
||||
s32 rf_a2;
|
||||
s32 rf_b2;
|
||||
};
|
||||
|
||||
enum tda18271_pll {
|
||||
|
|
@ -109,11 +109,12 @@ struct tda18271_priv {
|
|||
enum tda18271_i2c_gate gate;
|
||||
enum tda18271_ver id;
|
||||
enum tda18271_output_options output_opt;
|
||||
enum tda18271_small_i2c small_i2c;
|
||||
|
||||
unsigned int config; /* interface to saa713x / tda829x */
|
||||
unsigned int tm_rfcal;
|
||||
unsigned int cal_initialized:1;
|
||||
unsigned int small_i2c:1;
|
||||
|
||||
u8 tm_rfcal;
|
||||
|
||||
struct tda18271_map_layout *maps;
|
||||
struct tda18271_std_map std;
|
||||
|
|
@ -135,27 +136,37 @@ extern int tda18271_debug;
|
|||
#define DBG_ADV 8
|
||||
#define DBG_CAL 16
|
||||
|
||||
#define tda_printk(kern, fmt, arg...) \
|
||||
printk(kern "%s: " fmt, __func__, ##arg)
|
||||
#define tda_printk(st, kern, fmt, arg...) do {\
|
||||
if (st) { \
|
||||
struct tda18271_priv *state = st; \
|
||||
printk(kern "%s: [%d-%04x|%s] " fmt, __func__, \
|
||||
i2c_adapter_id(state->i2c_props.adap), \
|
||||
state->i2c_props.addr, \
|
||||
(state->role == TDA18271_MASTER) \
|
||||
? "M" : "S", ##arg); \
|
||||
} else \
|
||||
printk(kern "%s: " fmt, __func__, ##arg); \
|
||||
} while (0)
|
||||
|
||||
#define tda_dprintk(lvl, fmt, arg...) do {\
|
||||
#define tda_dprintk(st, lvl, fmt, arg...) do {\
|
||||
if (tda18271_debug & lvl) \
|
||||
tda_printk(KERN_DEBUG, fmt, ##arg); } while (0)
|
||||
tda_printk(st, KERN_DEBUG, fmt, ##arg); } while (0)
|
||||
|
||||
#define tda_info(fmt, arg...) printk(KERN_INFO fmt, ##arg)
|
||||
#define tda_warn(fmt, arg...) tda_printk(KERN_WARNING, fmt, ##arg)
|
||||
#define tda_err(fmt, arg...) tda_printk(KERN_ERR, fmt, ##arg)
|
||||
#define tda_dbg(fmt, arg...) tda_dprintk(DBG_INFO, fmt, ##arg)
|
||||
#define tda_map(fmt, arg...) tda_dprintk(DBG_MAP, fmt, ##arg)
|
||||
#define tda_reg(fmt, arg...) tda_dprintk(DBG_REG, fmt, ##arg)
|
||||
#define tda_cal(fmt, arg...) tda_dprintk(DBG_CAL, fmt, ##arg)
|
||||
#define tda_warn(fmt, arg...) tda_printk(priv, KERN_WARNING, fmt, ##arg)
|
||||
#define tda_err(fmt, arg...) tda_printk(priv, KERN_ERR, fmt, ##arg)
|
||||
#define tda_dbg(fmt, arg...) tda_dprintk(priv, DBG_INFO, fmt, ##arg)
|
||||
#define tda_map(fmt, arg...) tda_dprintk(priv, DBG_MAP, fmt, ##arg)
|
||||
#define tda_reg(fmt, arg...) tda_dprintk(priv, DBG_REG, fmt, ##arg)
|
||||
#define tda_cal(fmt, arg...) tda_dprintk(priv, DBG_CAL, fmt, ##arg)
|
||||
|
||||
#define tda_fail(ret) \
|
||||
({ \
|
||||
int __ret; \
|
||||
__ret = (ret < 0); \
|
||||
if (__ret) \
|
||||
tda_printk(KERN_ERR, "error %d on line %d\n", ret, __LINE__);\
|
||||
tda_printk(priv, KERN_ERR, \
|
||||
"error %d on line %d\n", ret, __LINE__); \
|
||||
__ret; \
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -78,6 +78,12 @@ enum tda18271_output_options {
|
|||
TDA18271_OUTPUT_XT_OFF = 2,
|
||||
};
|
||||
|
||||
enum tda18271_small_i2c {
|
||||
TDA18271_39_BYTE_CHUNK_INIT = 0,
|
||||
TDA18271_16_BYTE_CHUNK_INIT = 1,
|
||||
TDA18271_08_BYTE_CHUNK_INIT = 2,
|
||||
};
|
||||
|
||||
struct tda18271_config {
|
||||
/* override default if freq / std settings (optional) */
|
||||
struct tda18271_std_map *std_map;
|
||||
|
|
@ -91,12 +97,12 @@ struct tda18271_config {
|
|||
/* output options that can be disabled */
|
||||
enum tda18271_output_options output_opt;
|
||||
|
||||
/* some i2c providers cant write all 39 registers at once */
|
||||
enum tda18271_small_i2c small_i2c;
|
||||
|
||||
/* force rf tracking filter calibration on startup */
|
||||
unsigned int rf_cal_on_startup:1;
|
||||
|
||||
/* some i2c providers cant write all 39 registers at once */
|
||||
unsigned int small_i2c:1;
|
||||
|
||||
/* interface to saa713x / tda829x */
|
||||
unsigned int config;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ module_param(debug, int, 0644);
|
|||
MODULE_PARM_DESC(debug, "enable verbose debug messages");
|
||||
|
||||
static int deemphasis_50;
|
||||
module_param(deemphasis_50, int, 0644);
|
||||
MODULE_PARM_DESC(deemphasis_50, "0 - 75us deemphasis; 1 - 50us deemphasis");
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
|
|
|||
|
|
@ -463,7 +463,7 @@ static int tda9887_set_insmod(struct dvb_frontend *fe)
|
|||
buf[1] &= ~cQSS;
|
||||
}
|
||||
|
||||
if (adjust >= 0x00 && adjust < 0x20) {
|
||||
if (adjust < 0x20) {
|
||||
buf[2] &= ~cTopMask;
|
||||
buf[2] |= adjust;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ struct xc5000_priv {
|
|||
u32 bandwidth;
|
||||
u8 video_standard;
|
||||
u8 rf_mode;
|
||||
u8 radio_input;
|
||||
};
|
||||
|
||||
/* Misc Defines */
|
||||
|
|
@ -632,8 +633,12 @@ static int xc5000_set_params(struct dvb_frontend *fe,
|
|||
struct xc5000_priv *priv = fe->tuner_priv;
|
||||
int ret;
|
||||
|
||||
if (xc5000_is_firmware_loaded(fe) != XC_RESULT_SUCCESS)
|
||||
xc_load_fw_and_init_tuner(fe);
|
||||
if (xc5000_is_firmware_loaded(fe) != XC_RESULT_SUCCESS) {
|
||||
if (xc_load_fw_and_init_tuner(fe) != XC_RESULT_SUCCESS) {
|
||||
dprintk(1, "Unable to load firmware and init tuner\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
dprintk(1, "%s() frequency=%d (Hz)\n", __func__, params->frequency);
|
||||
|
||||
|
|
@ -739,15 +744,12 @@ static int xc5000_is_firmware_loaded(struct dvb_frontend *fe)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int xc5000_set_analog_params(struct dvb_frontend *fe,
|
||||
static int xc5000_set_tv_freq(struct dvb_frontend *fe,
|
||||
struct analog_parameters *params)
|
||||
{
|
||||
struct xc5000_priv *priv = fe->tuner_priv;
|
||||
int ret;
|
||||
|
||||
if (xc5000_is_firmware_loaded(fe) != XC_RESULT_SUCCESS)
|
||||
xc_load_fw_and_init_tuner(fe);
|
||||
|
||||
dprintk(1, "%s() frequency=%d (in units of 62.5khz)\n",
|
||||
__func__, params->frequency);
|
||||
|
||||
|
|
@ -827,6 +829,86 @@ tune_channel:
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int xc5000_set_radio_freq(struct dvb_frontend *fe,
|
||||
struct analog_parameters *params)
|
||||
{
|
||||
struct xc5000_priv *priv = fe->tuner_priv;
|
||||
int ret = -EINVAL;
|
||||
u8 radio_input;
|
||||
|
||||
dprintk(1, "%s() frequency=%d (in units of khz)\n",
|
||||
__func__, params->frequency);
|
||||
|
||||
if (priv->radio_input == XC5000_RADIO_NOT_CONFIGURED) {
|
||||
dprintk(1, "%s() radio input not configured\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (priv->radio_input == XC5000_RADIO_FM1)
|
||||
radio_input = FM_Radio_INPUT1;
|
||||
else if (priv->radio_input == XC5000_RADIO_FM2)
|
||||
radio_input = FM_Radio_INPUT2;
|
||||
else {
|
||||
dprintk(1, "%s() unknown radio input %d\n", __func__,
|
||||
priv->radio_input);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
priv->freq_hz = params->frequency * 125 / 2;
|
||||
|
||||
priv->rf_mode = XC_RF_MODE_AIR;
|
||||
|
||||
ret = xc_SetTVStandard(priv, XC5000_Standard[radio_input].VideoMode,
|
||||
XC5000_Standard[radio_input].AudioMode);
|
||||
|
||||
if (ret != XC_RESULT_SUCCESS) {
|
||||
printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n");
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
|
||||
ret = xc_SetSignalSource(priv, priv->rf_mode);
|
||||
if (ret != XC_RESULT_SUCCESS) {
|
||||
printk(KERN_ERR
|
||||
"xc5000: xc_SetSignalSource(%d) failed\n",
|
||||
priv->rf_mode);
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
|
||||
xc_tune_channel(priv, priv->freq_hz, XC_TUNE_ANALOG);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xc5000_set_analog_params(struct dvb_frontend *fe,
|
||||
struct analog_parameters *params)
|
||||
{
|
||||
struct xc5000_priv *priv = fe->tuner_priv;
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (priv->i2c_props.adap == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
if (xc5000_is_firmware_loaded(fe) != XC_RESULT_SUCCESS) {
|
||||
if (xc_load_fw_and_init_tuner(fe) != XC_RESULT_SUCCESS) {
|
||||
dprintk(1, "Unable to load firmware and init tuner\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
switch (params->mode) {
|
||||
case V4L2_TUNER_RADIO:
|
||||
ret = xc5000_set_radio_freq(fe, params);
|
||||
break;
|
||||
case V4L2_TUNER_ANALOG_TV:
|
||||
case V4L2_TUNER_DIGITAL_TV:
|
||||
ret = xc5000_set_tv_freq(fe, params);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int xc5000_get_frequency(struct dvb_frontend *fe, u32 *freq)
|
||||
{
|
||||
struct xc5000_priv *priv = fe->tuner_priv;
|
||||
|
|
@ -1000,6 +1082,9 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
|
|||
priv->if_khz = cfg->if_khz;
|
||||
}
|
||||
|
||||
if (priv->radio_input == 0)
|
||||
priv->radio_input = cfg->radio_input;
|
||||
|
||||
/* Check if firmware has been loaded. It is possible that another
|
||||
instance of the driver has loaded the firmware.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -30,11 +30,17 @@ struct i2c_adapter;
|
|||
struct xc5000_config {
|
||||
u8 i2c_address;
|
||||
u32 if_khz;
|
||||
u8 radio_input;
|
||||
};
|
||||
|
||||
/* xc5000 callback command */
|
||||
#define XC5000_TUNER_RESET 0
|
||||
|
||||
/* Possible Radio inputs */
|
||||
#define XC5000_RADIO_NOT_CONFIGURED 0
|
||||
#define XC5000_RADIO_FM1 1
|
||||
#define XC5000_RADIO_FM2 2
|
||||
|
||||
/* For each bridge framework, when it attaches either analog or digital,
|
||||
* it has to store a reference back to its _core equivalent structure,
|
||||
* so that it can service the hardware by steering gpio's etc.
|
||||
|
|
|
|||
|
|
@ -215,7 +215,7 @@ static int cx24108_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend
|
|||
freq = 2150000; /* satellite IF is 950..2150MHz */
|
||||
|
||||
/* decide which VCO to use for the input frequency */
|
||||
for(i = 1; (i < ARRAY_SIZE(osci)) && (osci[i] < freq); i++);
|
||||
for(i = 1; (i < ARRAY_SIZE(osci) - 1) && (osci[i] < freq); i++);
|
||||
printk("cx24108 debug: select vco #%d (f=%d)\n",i,freq);
|
||||
band=bandsel[i];
|
||||
/* the gain values must be set by SetSymbolrate */
|
||||
|
|
|
|||
|
|
@ -510,7 +510,7 @@ static void dm1105_emit_key(struct work_struct *work)
|
|||
|
||||
data = (ircom >> 8) & 0x7f;
|
||||
|
||||
ir_input_keydown(ir->input_dev, &ir->ir, data, data);
|
||||
ir_input_keydown(ir->input_dev, &ir->ir, data);
|
||||
ir_input_nokey(ir->input_dev, &ir->ir);
|
||||
}
|
||||
|
||||
|
|
@ -589,7 +589,12 @@ int __devinit dm1105_ir_init(struct dm1105dvb *dm1105)
|
|||
snprintf(dm1105->ir.input_phys, sizeof(dm1105->ir.input_phys),
|
||||
"pci-%s/ir0", pci_name(dm1105->pdev));
|
||||
|
||||
ir_input_init(input_dev, &dm1105->ir.ir, ir_type, ir_codes);
|
||||
err = ir_input_init(input_dev, &dm1105->ir.ir, ir_type, ir_codes);
|
||||
if (err < 0) {
|
||||
input_free_device(input_dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
input_dev->name = "DVB on-card IR receiver";
|
||||
input_dev->phys = dm1105->ir.input_phys;
|
||||
input_dev->id.bustype = BUS_PCI;
|
||||
|
|
@ -608,6 +613,7 @@ int __devinit dm1105_ir_init(struct dm1105dvb *dm1105)
|
|||
|
||||
err = input_register_device(input_dev);
|
||||
if (err) {
|
||||
ir_input_free(input_dev);
|
||||
input_free_device(input_dev);
|
||||
return err;
|
||||
}
|
||||
|
|
@ -617,8 +623,8 @@ int __devinit dm1105_ir_init(struct dm1105dvb *dm1105)
|
|||
|
||||
void __devexit dm1105_ir_exit(struct dm1105dvb *dm1105)
|
||||
{
|
||||
ir_input_free(dm1105->ir.input_dev);
|
||||
input_unregister_device(dm1105->ir.input_dev);
|
||||
|
||||
}
|
||||
|
||||
static int __devinit dm1105dvb_hw_init(struct dm1105dvb *dm1105dvb)
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
#include <linux/string.h>
|
||||
#include <linux/crc32.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/div64.h>
|
||||
|
||||
#include "dvb_demux.h"
|
||||
|
||||
|
|
@ -44,6 +45,11 @@ module_param(dvb_demux_tscheck, int, 0644);
|
|||
MODULE_PARM_DESC(dvb_demux_tscheck,
|
||||
"enable transport stream continuity and TEI check");
|
||||
|
||||
static int dvb_demux_speedcheck;
|
||||
module_param(dvb_demux_speedcheck, int, 0644);
|
||||
MODULE_PARM_DESC(dvb_demux_speedcheck,
|
||||
"enable transport stream speed check");
|
||||
|
||||
#define dprintk_tscheck(x...) do { \
|
||||
if (dvb_demux_tscheck && printk_ratelimit()) \
|
||||
printk(x); \
|
||||
|
|
@ -387,6 +393,39 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
|
|||
u16 pid = ts_pid(buf);
|
||||
int dvr_done = 0;
|
||||
|
||||
if (dvb_demux_speedcheck) {
|
||||
struct timespec cur_time, delta_time;
|
||||
u64 speed_bytes, speed_timedelta;
|
||||
|
||||
demux->speed_pkts_cnt++;
|
||||
|
||||
/* show speed every SPEED_PKTS_INTERVAL packets */
|
||||
if (!(demux->speed_pkts_cnt % SPEED_PKTS_INTERVAL)) {
|
||||
cur_time = current_kernel_time();
|
||||
|
||||
if (demux->speed_last_time.tv_sec != 0 &&
|
||||
demux->speed_last_time.tv_nsec != 0) {
|
||||
delta_time = timespec_sub(cur_time,
|
||||
demux->speed_last_time);
|
||||
speed_bytes = (u64)demux->speed_pkts_cnt
|
||||
* 188 * 8;
|
||||
/* convert to 1024 basis */
|
||||
speed_bytes = 1000 * div64_u64(speed_bytes,
|
||||
1024);
|
||||
speed_timedelta =
|
||||
(u64)timespec_to_ns(&delta_time);
|
||||
speed_timedelta = div64_u64(speed_timedelta,
|
||||
1000000); /* nsec -> usec */
|
||||
printk(KERN_INFO "TS speed %llu Kbits/sec \n",
|
||||
div64_u64(speed_bytes,
|
||||
speed_timedelta));
|
||||
};
|
||||
|
||||
demux->speed_last_time = cur_time;
|
||||
demux->speed_pkts_cnt = 0;
|
||||
};
|
||||
};
|
||||
|
||||
if (dvb_demux_tscheck) {
|
||||
if (!demux->cnt_storage)
|
||||
demux->cnt_storage = vmalloc(MAX_PID + 1);
|
||||
|
|
|
|||
|
|
@ -44,6 +44,8 @@
|
|||
|
||||
#define MAX_PID 0x1fff
|
||||
|
||||
#define SPEED_PKTS_INTERVAL 50000
|
||||
|
||||
struct dvb_demux_filter {
|
||||
struct dmx_section_filter filter;
|
||||
u8 maskandmode[DMX_MAX_FILTER_SIZE];
|
||||
|
|
@ -131,6 +133,9 @@ struct dvb_demux {
|
|||
spinlock_t lock;
|
||||
|
||||
uint8_t *cnt_storage; /* for TS continuity check */
|
||||
|
||||
struct timespec speed_last_time; /* for TS speed check */
|
||||
uint32_t speed_pkts_cnt; /* for TS speed check */
|
||||
};
|
||||
|
||||
int dvb_dmx_init(struct dvb_demux *dvbdemux);
|
||||
|
|
|
|||
|
|
@ -895,104 +895,27 @@ static int dvb_frontend_clear_cache(struct dvb_frontend *fe)
|
|||
}
|
||||
|
||||
static struct dtv_cmds_h dtv_cmds[] = {
|
||||
[DTV_TUNE] = {
|
||||
.name = "DTV_TUNE",
|
||||
.cmd = DTV_TUNE,
|
||||
.set = 1,
|
||||
},
|
||||
[DTV_CLEAR] = {
|
||||
.name = "DTV_CLEAR",
|
||||
.cmd = DTV_CLEAR,
|
||||
.set = 1,
|
||||
},
|
||||
_DTV_CMD(DTV_TUNE, 1, 0),
|
||||
_DTV_CMD(DTV_CLEAR, 1, 0),
|
||||
|
||||
/* Set */
|
||||
[DTV_FREQUENCY] = {
|
||||
.name = "DTV_FREQUENCY",
|
||||
.cmd = DTV_FREQUENCY,
|
||||
.set = 1,
|
||||
},
|
||||
[DTV_BANDWIDTH_HZ] = {
|
||||
.name = "DTV_BANDWIDTH_HZ",
|
||||
.cmd = DTV_BANDWIDTH_HZ,
|
||||
.set = 1,
|
||||
},
|
||||
[DTV_MODULATION] = {
|
||||
.name = "DTV_MODULATION",
|
||||
.cmd = DTV_MODULATION,
|
||||
.set = 1,
|
||||
},
|
||||
[DTV_INVERSION] = {
|
||||
.name = "DTV_INVERSION",
|
||||
.cmd = DTV_INVERSION,
|
||||
.set = 1,
|
||||
},
|
||||
[DTV_DISEQC_MASTER] = {
|
||||
.name = "DTV_DISEQC_MASTER",
|
||||
.cmd = DTV_DISEQC_MASTER,
|
||||
.set = 1,
|
||||
.buffer = 1,
|
||||
},
|
||||
[DTV_SYMBOL_RATE] = {
|
||||
.name = "DTV_SYMBOL_RATE",
|
||||
.cmd = DTV_SYMBOL_RATE,
|
||||
.set = 1,
|
||||
},
|
||||
[DTV_INNER_FEC] = {
|
||||
.name = "DTV_INNER_FEC",
|
||||
.cmd = DTV_INNER_FEC,
|
||||
.set = 1,
|
||||
},
|
||||
[DTV_VOLTAGE] = {
|
||||
.name = "DTV_VOLTAGE",
|
||||
.cmd = DTV_VOLTAGE,
|
||||
.set = 1,
|
||||
},
|
||||
[DTV_TONE] = {
|
||||
.name = "DTV_TONE",
|
||||
.cmd = DTV_TONE,
|
||||
.set = 1,
|
||||
},
|
||||
[DTV_PILOT] = {
|
||||
.name = "DTV_PILOT",
|
||||
.cmd = DTV_PILOT,
|
||||
.set = 1,
|
||||
},
|
||||
[DTV_ROLLOFF] = {
|
||||
.name = "DTV_ROLLOFF",
|
||||
.cmd = DTV_ROLLOFF,
|
||||
.set = 1,
|
||||
},
|
||||
[DTV_DELIVERY_SYSTEM] = {
|
||||
.name = "DTV_DELIVERY_SYSTEM",
|
||||
.cmd = DTV_DELIVERY_SYSTEM,
|
||||
.set = 1,
|
||||
},
|
||||
[DTV_HIERARCHY] = {
|
||||
.name = "DTV_HIERARCHY",
|
||||
.cmd = DTV_HIERARCHY,
|
||||
.set = 1,
|
||||
},
|
||||
[DTV_CODE_RATE_HP] = {
|
||||
.name = "DTV_CODE_RATE_HP",
|
||||
.cmd = DTV_CODE_RATE_HP,
|
||||
.set = 1,
|
||||
},
|
||||
[DTV_CODE_RATE_LP] = {
|
||||
.name = "DTV_CODE_RATE_LP",
|
||||
.cmd = DTV_CODE_RATE_LP,
|
||||
.set = 1,
|
||||
},
|
||||
[DTV_GUARD_INTERVAL] = {
|
||||
.name = "DTV_GUARD_INTERVAL",
|
||||
.cmd = DTV_GUARD_INTERVAL,
|
||||
.set = 1,
|
||||
},
|
||||
[DTV_TRANSMISSION_MODE] = {
|
||||
.name = "DTV_TRANSMISSION_MODE",
|
||||
.cmd = DTV_TRANSMISSION_MODE,
|
||||
.set = 1,
|
||||
},
|
||||
_DTV_CMD(DTV_FREQUENCY, 1, 0),
|
||||
_DTV_CMD(DTV_BANDWIDTH_HZ, 1, 0),
|
||||
_DTV_CMD(DTV_MODULATION, 1, 0),
|
||||
_DTV_CMD(DTV_INVERSION, 1, 0),
|
||||
_DTV_CMD(DTV_DISEQC_MASTER, 1, 1),
|
||||
_DTV_CMD(DTV_SYMBOL_RATE, 1, 0),
|
||||
_DTV_CMD(DTV_INNER_FEC, 1, 0),
|
||||
_DTV_CMD(DTV_VOLTAGE, 1, 0),
|
||||
_DTV_CMD(DTV_TONE, 1, 0),
|
||||
_DTV_CMD(DTV_PILOT, 1, 0),
|
||||
_DTV_CMD(DTV_ROLLOFF, 1, 0),
|
||||
_DTV_CMD(DTV_DELIVERY_SYSTEM, 1, 0),
|
||||
_DTV_CMD(DTV_HIERARCHY, 1, 0),
|
||||
_DTV_CMD(DTV_CODE_RATE_HP, 1, 0),
|
||||
_DTV_CMD(DTV_CODE_RATE_LP, 1, 0),
|
||||
_DTV_CMD(DTV_GUARD_INTERVAL, 1, 0),
|
||||
_DTV_CMD(DTV_TRANSMISSION_MODE, 1, 0),
|
||||
|
||||
_DTV_CMD(DTV_ISDBT_PARTIAL_RECEPTION, 1, 0),
|
||||
_DTV_CMD(DTV_ISDBT_SOUND_BROADCASTING, 1, 0),
|
||||
|
|
@ -1035,43 +958,13 @@ static struct dtv_cmds_h dtv_cmds[] = {
|
|||
_DTV_CMD(DTV_ISDBS_TS_ID, 1, 0),
|
||||
|
||||
/* Get */
|
||||
[DTV_DISEQC_SLAVE_REPLY] = {
|
||||
.name = "DTV_DISEQC_SLAVE_REPLY",
|
||||
.cmd = DTV_DISEQC_SLAVE_REPLY,
|
||||
.set = 0,
|
||||
.buffer = 1,
|
||||
},
|
||||
|
||||
[DTV_API_VERSION] = {
|
||||
.name = "DTV_API_VERSION",
|
||||
.cmd = DTV_API_VERSION,
|
||||
.set = 0,
|
||||
},
|
||||
[DTV_CODE_RATE_HP] = {
|
||||
.name = "DTV_CODE_RATE_HP",
|
||||
.cmd = DTV_CODE_RATE_HP,
|
||||
.set = 0,
|
||||
},
|
||||
[DTV_CODE_RATE_LP] = {
|
||||
.name = "DTV_CODE_RATE_LP",
|
||||
.cmd = DTV_CODE_RATE_LP,
|
||||
.set = 0,
|
||||
},
|
||||
[DTV_GUARD_INTERVAL] = {
|
||||
.name = "DTV_GUARD_INTERVAL",
|
||||
.cmd = DTV_GUARD_INTERVAL,
|
||||
.set = 0,
|
||||
},
|
||||
[DTV_TRANSMISSION_MODE] = {
|
||||
.name = "DTV_TRANSMISSION_MODE",
|
||||
.cmd = DTV_TRANSMISSION_MODE,
|
||||
.set = 0,
|
||||
},
|
||||
[DTV_HIERARCHY] = {
|
||||
.name = "DTV_HIERARCHY",
|
||||
.cmd = DTV_HIERARCHY,
|
||||
.set = 0,
|
||||
},
|
||||
_DTV_CMD(DTV_DISEQC_SLAVE_REPLY, 0, 1),
|
||||
_DTV_CMD(DTV_API_VERSION, 0, 0),
|
||||
_DTV_CMD(DTV_CODE_RATE_HP, 0, 0),
|
||||
_DTV_CMD(DTV_CODE_RATE_LP, 0, 0),
|
||||
_DTV_CMD(DTV_GUARD_INTERVAL, 0, 0),
|
||||
_DTV_CMD(DTV_TRANSMISSION_MODE, 0, 0),
|
||||
_DTV_CMD(DTV_HIERARCHY, 0, 0),
|
||||
};
|
||||
|
||||
static void dtv_property_dump(struct dtv_property *tvp)
|
||||
|
|
@ -1712,7 +1605,18 @@ static int dvb_frontend_ioctl_legacy(struct inode *inode, struct file *file,
|
|||
struct dvb_device *dvbdev = file->private_data;
|
||||
struct dvb_frontend *fe = dvbdev->priv;
|
||||
struct dvb_frontend_private *fepriv = fe->frontend_priv;
|
||||
int err = -EOPNOTSUPP;
|
||||
int cb_err, err = -EOPNOTSUPP;
|
||||
|
||||
if (fe->dvb->fe_ioctl_override) {
|
||||
cb_err = fe->dvb->fe_ioctl_override(fe, cmd, parg,
|
||||
DVB_FE_IOCTL_PRE);
|
||||
if (cb_err < 0)
|
||||
return cb_err;
|
||||
if (cb_err > 0)
|
||||
return 0;
|
||||
/* fe_ioctl_override returning 0 allows
|
||||
* dvb-core to continue handling the ioctl */
|
||||
}
|
||||
|
||||
switch (cmd) {
|
||||
case FE_GET_INFO: {
|
||||
|
|
@ -1978,6 +1882,13 @@ static int dvb_frontend_ioctl_legacy(struct inode *inode, struct file *file,
|
|||
break;
|
||||
};
|
||||
|
||||
if (fe->dvb->fe_ioctl_override) {
|
||||
cb_err = fe->dvb->fe_ioctl_override(fe, cmd, parg,
|
||||
DVB_FE_IOCTL_POST);
|
||||
if (cb_err < 0)
|
||||
return cb_err;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -54,6 +54,8 @@
|
|||
module_param_array(adapter_nr, short, NULL, 0444); \
|
||||
MODULE_PARM_DESC(adapter_nr, "DVB adapter numbers")
|
||||
|
||||
struct dvb_frontend;
|
||||
|
||||
struct dvb_adapter {
|
||||
int num;
|
||||
struct list_head list_head;
|
||||
|
|
@ -69,6 +71,32 @@ struct dvb_adapter {
|
|||
int mfe_shared; /* indicates mutually exclusive frontends */
|
||||
struct dvb_device *mfe_dvbdev; /* frontend device in use */
|
||||
struct mutex mfe_lock; /* access lock for thread creation */
|
||||
|
||||
/* Allow the adapter/bridge driver to perform an action before and/or
|
||||
* after the core handles an ioctl:
|
||||
*
|
||||
* DVB_FE_IOCTL_PRE indicates that the ioctl has not yet been handled.
|
||||
* DVB_FE_IOCTL_POST indicates that the ioctl has been handled.
|
||||
*
|
||||
* When DVB_FE_IOCTL_PRE is passed to the callback as the stage arg:
|
||||
*
|
||||
* return 0 to allow dvb-core to handle the ioctl.
|
||||
* return a positive int to prevent dvb-core from handling the ioctl,
|
||||
* and exit without error.
|
||||
* return a negative int to prevent dvb-core from handling the ioctl,
|
||||
* and return that value as an error.
|
||||
*
|
||||
* When DVB_FE_IOCTL_POST is passed to the callback as the stage arg:
|
||||
*
|
||||
* return 0 to allow the dvb_frontend ioctl handler to exit normally.
|
||||
* return a negative int to cause the dvb_frontend ioctl handler to
|
||||
* return that value as an error.
|
||||
*/
|
||||
#define DVB_FE_IOCTL_PRE 0
|
||||
#define DVB_FE_IOCTL_POST 1
|
||||
int (*fe_ioctl_override)(struct dvb_frontend *fe,
|
||||
unsigned int cmd, void *parg,
|
||||
unsigned int stage);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -322,3 +322,11 @@ config DVB_USB_FRIIO
|
|||
depends on DVB_USB
|
||||
help
|
||||
Say Y here to support the Japanese DTV receiver Friio.
|
||||
|
||||
config DVB_USB_EC168
|
||||
tristate "E3C EC168 DVB-T USB2.0 support"
|
||||
depends on DVB_USB && EXPERIMENTAL
|
||||
select DVB_EC100
|
||||
select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
|
||||
help
|
||||
Say Y here to support the E3C EC168 DVB-T USB2.0 receiver.
|
||||
|
|
|
|||
|
|
@ -82,6 +82,9 @@ obj-$(CONFIG_DVB_USB_CE6230) += dvb-usb-ce6230.o
|
|||
dvb-usb-friio-objs = friio.o friio-fe.o
|
||||
obj-$(CONFIG_DVB_USB_FRIIO) += dvb-usb-friio.o
|
||||
|
||||
dvb-usb-ec168-objs = ec168.o
|
||||
obj-$(CONFIG_DVB_USB_EC168) += dvb-usb-ec168.o
|
||||
|
||||
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
|
||||
# due to tuner-xc3028
|
||||
EXTRA_CFLAGS += -Idrivers/media/common/tuners
|
||||
|
|
|
|||
|
|
@ -730,7 +730,7 @@ static int af9015_read_config(struct usb_device *udev)
|
|||
goto error;
|
||||
deb_info("%s: IR mode:%d\n", __func__, val);
|
||||
for (i = 0; i < af9015_properties_count; i++) {
|
||||
if (val == AF9015_IR_MODE_DISABLED || val == 0x04) {
|
||||
if (val == AF9015_IR_MODE_DISABLED) {
|
||||
af9015_properties[i].rc_key_map = NULL;
|
||||
af9015_properties[i].rc_key_map_size = 0;
|
||||
} else if (dvb_usb_af9015_remote) {
|
||||
|
|
@ -868,6 +868,16 @@ static int af9015_read_config(struct usb_device *udev)
|
|||
af9015_config.ir_table_size =
|
||||
ARRAY_SIZE(af9015_ir_table_avermedia);
|
||||
break;
|
||||
case USB_VID_MSI_2:
|
||||
af9015_properties[i].rc_key_map =
|
||||
af9015_rc_keys_msi_digivox_iii;
|
||||
af9015_properties[i].rc_key_map_size =
|
||||
ARRAY_SIZE(af9015_rc_keys_msi_digivox_iii);
|
||||
af9015_config.ir_table =
|
||||
af9015_ir_table_msi_digivox_iii;
|
||||
af9015_config.ir_table_size =
|
||||
ARRAY_SIZE(af9015_ir_table_msi_digivox_iii);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1283,6 +1293,8 @@ static struct usb_device_id af9015_usb_table[] = {
|
|||
{USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_MC810)},
|
||||
{USB_DEVICE(USB_VID_KYE, USB_PID_GENIUS_TVGO_DVB_T03)},
|
||||
/* 25 */{USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U_2)},
|
||||
{USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_T)},
|
||||
{USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV20)},
|
||||
{0},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(usb, af9015_usb_table);
|
||||
|
|
@ -1296,7 +1308,7 @@ static struct dvb_usb_device_properties af9015_properties[] = {
|
|||
.firmware = "dvb-usb-af9015.fw",
|
||||
.no_reconnect = 1,
|
||||
|
||||
.size_of_priv = sizeof(struct af9015_state), \
|
||||
.size_of_priv = sizeof(struct af9015_state),
|
||||
|
||||
.num_adapters = 2,
|
||||
.adapter = {
|
||||
|
|
@ -1402,7 +1414,7 @@ static struct dvb_usb_device_properties af9015_properties[] = {
|
|||
.firmware = "dvb-usb-af9015.fw",
|
||||
.no_reconnect = 1,
|
||||
|
||||
.size_of_priv = sizeof(struct af9015_state), \
|
||||
.size_of_priv = sizeof(struct af9015_state),
|
||||
|
||||
.num_adapters = 2,
|
||||
.adapter = {
|
||||
|
|
@ -1508,7 +1520,7 @@ static struct dvb_usb_device_properties af9015_properties[] = {
|
|||
.firmware = "dvb-usb-af9015.fw",
|
||||
.no_reconnect = 1,
|
||||
|
||||
.size_of_priv = sizeof(struct af9015_state), \
|
||||
.size_of_priv = sizeof(struct af9015_state),
|
||||
|
||||
.num_adapters = 2,
|
||||
.adapter = {
|
||||
|
|
@ -1554,7 +1566,7 @@ static struct dvb_usb_device_properties af9015_properties[] = {
|
|||
|
||||
.i2c_algo = &af9015_i2c_algo,
|
||||
|
||||
.num_device_descs = 4, /* max 9 */
|
||||
.num_device_descs = 6, /* max 9 */
|
||||
.devices = {
|
||||
{
|
||||
.name = "AverMedia AVerTV Volar GPS 805 (A805)",
|
||||
|
|
@ -1577,6 +1589,17 @@ static struct dvb_usb_device_properties af9015_properties[] = {
|
|||
.cold_ids = {&af9015_usb_table[24], NULL},
|
||||
.warm_ids = {NULL},
|
||||
},
|
||||
{
|
||||
.name = "KWorld PlusTV DVB-T PCI Pro Card " \
|
||||
"(DVB-T PC160-T)",
|
||||
.cold_ids = {&af9015_usb_table[26], NULL},
|
||||
.warm_ids = {NULL},
|
||||
},
|
||||
{
|
||||
.name = "Sveon STV20 Tuner USB DVB-T HDTV",
|
||||
.cold_ids = {&af9015_usb_table[27], NULL},
|
||||
.warm_ids = {NULL},
|
||||
},
|
||||
}
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -95,6 +95,7 @@ enum af9015_ir_mode {
|
|||
AF9015_IR_MODE_HID,
|
||||
AF9015_IR_MODE_RLC,
|
||||
AF9015_IR_MODE_RC6,
|
||||
AF9015_IR_MODE_POLLING, /* just guess */
|
||||
};
|
||||
|
||||
struct af9015_state {
|
||||
|
|
@ -119,6 +120,7 @@ enum af9015_remote {
|
|||
/* 5 */ AF9015_REMOTE_AVERMEDIA_KS,
|
||||
};
|
||||
|
||||
/* LeadTek - Y04G0051 */
|
||||
/* Leadtek WinFast DTV Dongle Gold */
|
||||
static struct dvb_usb_rc_key af9015_rc_keys_leadtek[] = {
|
||||
{ 0x001e, KEY_1 },
|
||||
|
|
@ -131,64 +133,96 @@ static struct dvb_usb_rc_key af9015_rc_keys_leadtek[] = {
|
|||
{ 0x0025, KEY_8 },
|
||||
{ 0x0026, KEY_9 },
|
||||
{ 0x0027, KEY_0 },
|
||||
{ 0x0028, KEY_ENTER },
|
||||
{ 0x004f, KEY_VOLUMEUP },
|
||||
{ 0x0050, KEY_VOLUMEDOWN },
|
||||
{ 0x0051, KEY_CHANNELDOWN },
|
||||
{ 0x0052, KEY_CHANNELUP },
|
||||
{ 0x0028, KEY_OK },
|
||||
{ 0x004f, KEY_RIGHT },
|
||||
{ 0x0050, KEY_LEFT },
|
||||
{ 0x0051, KEY_DOWN },
|
||||
{ 0x0052, KEY_UP },
|
||||
{ 0x011a, KEY_POWER2 },
|
||||
{ 0x04b4, KEY_TV },
|
||||
{ 0x04b3, KEY_RED },
|
||||
{ 0x04b2, KEY_GREEN },
|
||||
{ 0x04b1, KEY_YELLOW },
|
||||
{ 0x04b0, KEY_BLUE },
|
||||
{ 0x003d, KEY_TEXT },
|
||||
{ 0x0113, KEY_SLEEP },
|
||||
{ 0x0010, KEY_MUTE },
|
||||
{ 0x0105, KEY_ESC },
|
||||
{ 0x0009, KEY_SCREEN },
|
||||
{ 0x010f, KEY_MENU },
|
||||
{ 0x003f, KEY_CHANNEL },
|
||||
{ 0x0013, KEY_REWIND },
|
||||
{ 0x0012, KEY_PLAY },
|
||||
{ 0x0011, KEY_FASTFORWARD },
|
||||
{ 0x0005, KEY_PREVIOUS },
|
||||
{ 0x0029, KEY_STOP },
|
||||
{ 0x002b, KEY_NEXT },
|
||||
{ 0x0041, KEY_EPG },
|
||||
{ 0x0019, KEY_VIDEO },
|
||||
{ 0x0016, KEY_AUDIO },
|
||||
{ 0x0037, KEY_DOT },
|
||||
{ 0x002a, KEY_AGAIN },
|
||||
{ 0x002c, KEY_CAMERA },
|
||||
{ 0x003c, KEY_NEW },
|
||||
{ 0x0115, KEY_RECORD },
|
||||
{ 0x010b, KEY_TIME },
|
||||
{ 0x0043, KEY_VOLUMEUP },
|
||||
{ 0x0042, KEY_VOLUMEDOWN },
|
||||
{ 0x004b, KEY_CHANNELUP },
|
||||
{ 0x004e, KEY_CHANNELDOWN },
|
||||
};
|
||||
|
||||
static u8 af9015_ir_table_leadtek[] = {
|
||||
0x03, 0xfc, 0x00, 0xff, 0x1a, 0x01, 0x00,
|
||||
0x03, 0xfc, 0x56, 0xa9, 0x00, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x4b, 0xb4, 0x00, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x4c, 0xb3, 0xb2, 0x04, 0x00,
|
||||
0x03, 0xfc, 0x4d, 0xb2, 0x00, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x4e, 0xb1, 0x00, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x1f, 0xe0, 0x3d, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x40, 0xbf, 0x13, 0x01, 0x00,
|
||||
0x03, 0xfc, 0x14, 0xeb, 0x10, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x49, 0xb6, 0x05, 0x01, 0x00,
|
||||
0x03, 0xfc, 0x50, 0xaf, 0x29, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x0c, 0xf3, 0x52, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x03, 0xfc, 0x09, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x08, 0xf7, 0x50, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x13, 0xec, 0x28, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x04, 0xfb, 0x4f, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x4f, 0xb0, 0x0f, 0x01, 0x00,
|
||||
0x03, 0xfc, 0x10, 0xef, 0x51, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x51, 0xae, 0x3f, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x42, 0xbd, 0x13, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x43, 0xbc, 0x00, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x44, 0xbb, 0x11, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x52, 0xad, 0x19, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x54, 0xab, 0x05, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x46, 0xb9, 0x29, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x55, 0xaa, 0x2b, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x53, 0xac, 0x41, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x05, 0xfa, 0x1e, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x06, 0xf9, 0x1f, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x07, 0xf8, 0x20, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x1e, 0xe1, 0x19, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x09, 0xf6, 0x21, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x0a, 0xf5, 0x22, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x0b, 0xf4, 0x23, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x1b, 0xe4, 0x16, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x0d, 0xf2, 0x24, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x0e, 0xf1, 0x25, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x0f, 0xf0, 0x26, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x16, 0xe9, 0x28, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x41, 0xbe, 0x37, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x12, 0xed, 0x27, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x11, 0xee, 0x2a, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x48, 0xb7, 0x2c, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x4a, 0xb5, 0x3c, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x47, 0xb8, 0x15, 0x01, 0x00,
|
||||
0x03, 0xfc, 0x45, 0xba, 0x0b, 0x01, 0x00,
|
||||
0x03, 0xfc, 0x5e, 0xa1, 0x43, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x5a, 0xa5, 0x42, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x5b, 0xa4, 0x4b, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x5f, 0xa0, 0x4e, 0x00, 0x00,
|
||||
0x03, 0xfc, 0x00, 0xff, 0x1a, 0x01, 0x00, /* KEY_POWER2 */
|
||||
0x03, 0xfc, 0x56, 0xa9, 0xb4, 0x04, 0x00, /* KEY_TV */
|
||||
0x03, 0xfc, 0x4b, 0xb4, 0xb3, 0x04, 0x00, /* KEY_RED */
|
||||
0x03, 0xfc, 0x4c, 0xb3, 0xb2, 0x04, 0x00, /* KEY_GREEN */
|
||||
0x03, 0xfc, 0x4d, 0xb2, 0xb1, 0x04, 0x00, /* KEY_YELLOW */
|
||||
0x03, 0xfc, 0x4e, 0xb1, 0xb0, 0x04, 0x00, /* KEY_BLUE */
|
||||
0x03, 0xfc, 0x1f, 0xe0, 0x3d, 0x00, 0x00, /* KEY_TEXT */
|
||||
0x03, 0xfc, 0x40, 0xbf, 0x13, 0x01, 0x00, /* KEY_SLEEP */
|
||||
0x03, 0xfc, 0x14, 0xeb, 0x10, 0x00, 0x00, /* KEY_MUTE */
|
||||
0x03, 0xfc, 0x49, 0xb6, 0x05, 0x01, 0x00, /* KEY_ESC */
|
||||
0x03, 0xfc, 0x50, 0xaf, 0x29, 0x00, 0x00, /* KEY_STOP (1)*/
|
||||
0x03, 0xfc, 0x0c, 0xf3, 0x52, 0x00, 0x00, /* KEY_UP */
|
||||
0x03, 0xfc, 0x03, 0xfc, 0x09, 0x00, 0x00, /* KEY_SCREEN */
|
||||
0x03, 0xfc, 0x08, 0xf7, 0x50, 0x00, 0x00, /* KEY_LEFT */
|
||||
0x03, 0xfc, 0x13, 0xec, 0x28, 0x00, 0x00, /* KEY_OK (1) */
|
||||
0x03, 0xfc, 0x04, 0xfb, 0x4f, 0x00, 0x00, /* KEY_RIGHT */
|
||||
0x03, 0xfc, 0x4f, 0xb0, 0x0f, 0x01, 0x00, /* KEY_MENU */
|
||||
0x03, 0xfc, 0x10, 0xef, 0x51, 0x00, 0x00, /* KEY_DOWN */
|
||||
0x03, 0xfc, 0x51, 0xae, 0x3f, 0x00, 0x00, /* KEY_CHANNEL */
|
||||
0x03, 0xfc, 0x42, 0xbd, 0x13, 0x00, 0x00, /* KEY_REWIND */
|
||||
0x03, 0xfc, 0x43, 0xbc, 0x12, 0x00, 0x00, /* KEY_PLAY */
|
||||
0x03, 0xfc, 0x44, 0xbb, 0x11, 0x00, 0x00, /* KEY_FASTFORWARD */
|
||||
0x03, 0xfc, 0x52, 0xad, 0x19, 0x00, 0x00, /* KEY_VIDEO (1) */
|
||||
0x03, 0xfc, 0x54, 0xab, 0x05, 0x00, 0x00, /* KEY_PREVIOUS */
|
||||
0x03, 0xfc, 0x46, 0xb9, 0x29, 0x00, 0x00, /* KEY_STOP (2) */
|
||||
0x03, 0xfc, 0x55, 0xaa, 0x2b, 0x00, 0x00, /* KEY_NEXT */
|
||||
0x03, 0xfc, 0x53, 0xac, 0x41, 0x00, 0x00, /* KEY_EPG */
|
||||
0x03, 0xfc, 0x05, 0xfa, 0x1e, 0x00, 0x00, /* KEY_1 */
|
||||
0x03, 0xfc, 0x06, 0xf9, 0x1f, 0x00, 0x00, /* KEY_2 */
|
||||
0x03, 0xfc, 0x07, 0xf8, 0x20, 0x00, 0x00, /* KEY_3 */
|
||||
0x03, 0xfc, 0x1e, 0xe1, 0x19, 0x00, 0x00, /* KEY_VIDEO (2) */
|
||||
0x03, 0xfc, 0x09, 0xf6, 0x21, 0x00, 0x00, /* KEY_4 */
|
||||
0x03, 0xfc, 0x0a, 0xf5, 0x22, 0x00, 0x00, /* KEY_5 */
|
||||
0x03, 0xfc, 0x0b, 0xf4, 0x23, 0x00, 0x00, /* KEY_6 */
|
||||
0x03, 0xfc, 0x1b, 0xe4, 0x16, 0x00, 0x00, /* KEY_AUDIO */
|
||||
0x03, 0xfc, 0x0d, 0xf2, 0x24, 0x00, 0x00, /* KEY_7 */
|
||||
0x03, 0xfc, 0x0e, 0xf1, 0x25, 0x00, 0x00, /* KEY_8 */
|
||||
0x03, 0xfc, 0x0f, 0xf0, 0x26, 0x00, 0x00, /* KEY_9 */
|
||||
0x03, 0xfc, 0x16, 0xe9, 0x28, 0x00, 0x00, /* KEY_OK (2) */
|
||||
0x03, 0xfc, 0x41, 0xbe, 0x37, 0x00, 0x00, /* KEY_DOT */
|
||||
0x03, 0xfc, 0x12, 0xed, 0x27, 0x00, 0x00, /* KEY_0 */
|
||||
0x03, 0xfc, 0x11, 0xee, 0x2a, 0x00, 0x00, /* KEY_AGAIN */
|
||||
0x03, 0xfc, 0x48, 0xb7, 0x2c, 0x00, 0x00, /* KEY_CAMERA */
|
||||
0x03, 0xfc, 0x4a, 0xb5, 0x3c, 0x00, 0x00, /* KEY_NEW */
|
||||
0x03, 0xfc, 0x47, 0xb8, 0x15, 0x01, 0x00, /* KEY_RECORD */
|
||||
0x03, 0xfc, 0x45, 0xba, 0x0b, 0x01, 0x00, /* KEY_TIME */
|
||||
0x03, 0xfc, 0x5e, 0xa1, 0x43, 0x00, 0x00, /* KEY_VOLUMEUP */
|
||||
0x03, 0xfc, 0x5a, 0xa5, 0x42, 0x00, 0x00, /* KEY_VOLUMEDOWN */
|
||||
0x03, 0xfc, 0x5b, 0xa4, 0x4b, 0x00, 0x00, /* KEY_CHANNELUP */
|
||||
0x03, 0xfc, 0x5f, 0xa0, 0x4e, 0x00, 0x00, /* KEY_CHANNELDOWN */
|
||||
};
|
||||
|
||||
/* TwinHan AzureWave AD-TU700(704J) */
|
||||
|
|
@ -746,4 +780,75 @@ static u8 af9015_ir_table_trekstor[] = {
|
|||
0x00, 0xff, 0x84, 0x7b, 0x27, 0x07, 0x00,
|
||||
};
|
||||
|
||||
/* MSI DIGIVOX mini III */
|
||||
static struct dvb_usb_rc_key af9015_rc_keys_msi_digivox_iii[] = {
|
||||
{ 0x0713, KEY_POWER }, /* [red power button] */
|
||||
{ 0x073b, KEY_VIDEO }, /* Source */
|
||||
{ 0x073e, KEY_ZOOM }, /* Zoom */
|
||||
{ 0x070b, KEY_POWER2 }, /* ShutDown */
|
||||
{ 0x071e, KEY_1 },
|
||||
{ 0x071f, KEY_2 },
|
||||
{ 0x0720, KEY_3 },
|
||||
{ 0x0721, KEY_4 },
|
||||
{ 0x0722, KEY_5 },
|
||||
{ 0x0723, KEY_6 },
|
||||
{ 0x0724, KEY_7 },
|
||||
{ 0x0725, KEY_8 },
|
||||
{ 0x0726, KEY_9 },
|
||||
{ 0x0727, KEY_0 },
|
||||
{ 0x0752, KEY_CHANNELUP }, /* CH+ */
|
||||
{ 0x0751, KEY_CHANNELDOWN }, /* CH- */
|
||||
{ 0x0750, KEY_VOLUMEUP }, /* Vol+ */
|
||||
{ 0x074f, KEY_VOLUMEDOWN }, /* Vol- */
|
||||
{ 0x0705, KEY_ESC }, /* [back up arrow] */
|
||||
{ 0x0708, KEY_OK }, /* [enter arrow] */
|
||||
{ 0x073f, KEY_RECORD }, /* Rec */
|
||||
{ 0x0716, KEY_STOP }, /* Stop */
|
||||
{ 0x072a, KEY_PLAY }, /* Play */
|
||||
{ 0x073c, KEY_MUTE }, /* Mute */
|
||||
{ 0x0718, KEY_UP },
|
||||
{ 0x0707, KEY_DOWN },
|
||||
{ 0x070f, KEY_LEFT },
|
||||
{ 0x0715, KEY_RIGHT },
|
||||
{ 0x0736, KEY_RED },
|
||||
{ 0x0737, KEY_GREEN },
|
||||
{ 0x072d, KEY_YELLOW },
|
||||
{ 0x072e, KEY_BLUE },
|
||||
};
|
||||
|
||||
static u8 af9015_ir_table_msi_digivox_iii[] = {
|
||||
0x61, 0xd6, 0x43, 0xbc, 0x13, 0x07, 0x00, /* KEY_POWER */
|
||||
0x61, 0xd6, 0x01, 0xfe, 0x3b, 0x07, 0x00, /* KEY_VIDEO */
|
||||
0x61, 0xd6, 0x0b, 0xf4, 0x3e, 0x07, 0x00, /* KEY_ZOOM */
|
||||
0x61, 0xd6, 0x03, 0xfc, 0x0b, 0x07, 0x00, /* KEY_POWER2 */
|
||||
0x61, 0xd6, 0x04, 0xfb, 0x1e, 0x07, 0x00, /* KEY_1 */
|
||||
0x61, 0xd6, 0x08, 0xf7, 0x1f, 0x07, 0x00, /* KEY_2 */
|
||||
0x61, 0xd6, 0x02, 0xfd, 0x20, 0x07, 0x00, /* KEY_3 */
|
||||
0x61, 0xd6, 0x0f, 0xf0, 0x21, 0x07, 0x00, /* KEY_4 */
|
||||
0x61, 0xd6, 0x05, 0xfa, 0x22, 0x07, 0x00, /* KEY_5 */
|
||||
0x61, 0xd6, 0x06, 0xf9, 0x23, 0x07, 0x00, /* KEY_6 */
|
||||
0x61, 0xd6, 0x0c, 0xf3, 0x24, 0x07, 0x00, /* KEY_7 */
|
||||
0x61, 0xd6, 0x0d, 0xf2, 0x25, 0x07, 0x00, /* KEY_8 */
|
||||
0x61, 0xd6, 0x0a, 0xf5, 0x26, 0x07, 0x00, /* KEY_9 */
|
||||
0x61, 0xd6, 0x11, 0xee, 0x27, 0x07, 0x00, /* KEY_0 */
|
||||
0x61, 0xd6, 0x09, 0xf6, 0x52, 0x07, 0x00, /* KEY_CHANNELUP */
|
||||
0x61, 0xd6, 0x07, 0xf8, 0x51, 0x07, 0x00, /* KEY_CHANNELDOWN */
|
||||
0x61, 0xd6, 0x0e, 0xf1, 0x50, 0x07, 0x00, /* KEY_VOLUMEUP */
|
||||
0x61, 0xd6, 0x13, 0xec, 0x4f, 0x07, 0x00, /* KEY_VOLUMEDOWN */
|
||||
0x61, 0xd6, 0x10, 0xef, 0x05, 0x07, 0x00, /* KEY_ESC */
|
||||
0x61, 0xd6, 0x12, 0xed, 0x08, 0x07, 0x00, /* KEY_OK */
|
||||
0x61, 0xd6, 0x14, 0xeb, 0x3f, 0x07, 0x00, /* KEY_RECORD */
|
||||
0x61, 0xd6, 0x15, 0xea, 0x16, 0x07, 0x00, /* KEY_STOP */
|
||||
0x61, 0xd6, 0x16, 0xe9, 0x2a, 0x07, 0x00, /* KEY_PLAY */
|
||||
0x61, 0xd6, 0x17, 0xe8, 0x3c, 0x07, 0x00, /* KEY_MUTE */
|
||||
0x61, 0xd6, 0x18, 0xe7, 0x18, 0x07, 0x00, /* KEY_UP */
|
||||
0x61, 0xd6, 0x19, 0xe6, 0x07, 0x07, 0x00, /* KEY_DOWN */
|
||||
0x61, 0xd6, 0x1a, 0xe5, 0x0f, 0x07, 0x00, /* KEY_LEFT */
|
||||
0x61, 0xd6, 0x1b, 0xe4, 0x15, 0x07, 0x00, /* KEY_RIGHT */
|
||||
0x61, 0xd6, 0x1c, 0xe3, 0x36, 0x07, 0x00, /* KEY_RED */
|
||||
0x61, 0xd6, 0x1d, 0xe2, 0x37, 0x07, 0x00, /* KEY_GREEN */
|
||||
0x61, 0xd6, 0x1e, 0xe1, 0x2d, 0x07, 0x00, /* KEY_YELLOW */
|
||||
0x61, 0xd6, 0x1f, 0xe0, 0x2e, 0x07, 0x00, /* KEY_BLUE */
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -36,9 +36,11 @@
|
|||
#include "tuner-xc2028.h"
|
||||
#include "tuner-simple.h"
|
||||
#include "mxl5005s.h"
|
||||
#include "max2165.h"
|
||||
#include "dib7000p.h"
|
||||
#include "dib0070.h"
|
||||
#include "lgs8gxx.h"
|
||||
#include "atbm8830.h"
|
||||
|
||||
/* debug */
|
||||
static int dvb_usb_cxusb_debug;
|
||||
|
|
@ -714,6 +716,11 @@ static struct mxl5005s_config d680_dmb_tuner = {
|
|||
.AgcMasterByte = 0x00,
|
||||
};
|
||||
|
||||
static struct max2165_config mygica_d689_max2165_cfg = {
|
||||
.i2c_address = 0x60,
|
||||
.osc_clk = 20
|
||||
};
|
||||
|
||||
/* Callbacks for DVB USB */
|
||||
static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
|
|
@ -813,6 +820,14 @@ static int cxusb_d680_dmb_tuner_attach(struct dvb_usb_adapter *adap)
|
|||
return (fe == NULL) ? -EIO : 0;
|
||||
}
|
||||
|
||||
static int cxusb_mygica_d689_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
struct dvb_frontend *fe;
|
||||
fe = dvb_attach(max2165_attach, adap->fe,
|
||||
&adap->dev->i2c_adap, &mygica_d689_max2165_cfg);
|
||||
return (fe == NULL) ? -EIO : 0;
|
||||
}
|
||||
|
||||
static int cxusb_cx22702_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
u8 b;
|
||||
|
|
@ -1160,6 +1175,55 @@ static int cxusb_d680_dmb_frontend_attach(struct dvb_usb_adapter *adap)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct atbm8830_config mygica_d689_atbm8830_cfg = {
|
||||
.prod = ATBM8830_PROD_8830,
|
||||
.demod_address = 0x40,
|
||||
.serial_ts = 0,
|
||||
.ts_sampling_edge = 1,
|
||||
.ts_clk_gated = 0,
|
||||
.osc_clk_freq = 30400, /* in kHz */
|
||||
.if_freq = 0, /* zero IF */
|
||||
.zif_swap_iq = 1,
|
||||
};
|
||||
|
||||
static int cxusb_mygica_d689_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
struct dvb_usb_device *d = adap->dev;
|
||||
|
||||
/* Select required USB configuration */
|
||||
if (usb_set_interface(d->udev, 0, 0) < 0)
|
||||
err("set interface failed");
|
||||
|
||||
/* Unblock all USB pipes */
|
||||
usb_clear_halt(d->udev,
|
||||
usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint));
|
||||
usb_clear_halt(d->udev,
|
||||
usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint));
|
||||
usb_clear_halt(d->udev,
|
||||
usb_rcvbulkpipe(d->udev, d->props.adapter[0].stream.endpoint));
|
||||
|
||||
|
||||
/* Reset the tuner */
|
||||
if (cxusb_d680_dmb_gpio_tuner(d, 0x07, 0) < 0) {
|
||||
err("clear tuner gpio failed");
|
||||
return -EIO;
|
||||
}
|
||||
msleep(100);
|
||||
if (cxusb_d680_dmb_gpio_tuner(d, 0x07, 1) < 0) {
|
||||
err("set tuner gpio failed");
|
||||
return -EIO;
|
||||
}
|
||||
msleep(100);
|
||||
|
||||
/* Attach frontend */
|
||||
adap->fe = dvb_attach(atbm8830_attach, &mygica_d689_atbm8830_cfg,
|
||||
&d->i2c_adap);
|
||||
if (adap->fe == NULL)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* DViCO has shipped two devices with the same USB ID, but only one of them
|
||||
* needs a firmware download. Check the device class details to see if they
|
||||
|
|
@ -1240,6 +1304,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties;
|
|||
static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_properties;
|
||||
static struct dvb_usb_device_properties cxusb_aver_a868r_properties;
|
||||
static struct dvb_usb_device_properties cxusb_d680_dmb_properties;
|
||||
static struct dvb_usb_device_properties cxusb_mygica_d689_properties;
|
||||
|
||||
static int cxusb_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
|
|
@ -1268,6 +1333,8 @@ static int cxusb_probe(struct usb_interface *intf,
|
|||
THIS_MODULE, NULL, adapter_nr) ||
|
||||
0 == dvb_usb_device_init(intf, &cxusb_d680_dmb_properties,
|
||||
THIS_MODULE, NULL, adapter_nr) ||
|
||||
0 == dvb_usb_device_init(intf, &cxusb_mygica_d689_properties,
|
||||
THIS_MODULE, NULL, adapter_nr) ||
|
||||
0)
|
||||
return 0;
|
||||
|
||||
|
|
@ -1294,6 +1361,7 @@ static struct usb_device_id cxusb_table [] = {
|
|||
{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_A868R) },
|
||||
{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_4_REV_2) },
|
||||
{ USB_DEVICE(USB_VID_CONEXANT, USB_PID_CONEXANT_D680_DMB) },
|
||||
{ USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_D689) },
|
||||
{} /* Terminating entry */
|
||||
};
|
||||
MODULE_DEVICE_TABLE (usb, cxusb_table);
|
||||
|
|
@ -1837,6 +1905,55 @@ static struct dvb_usb_device_properties cxusb_d680_dmb_properties = {
|
|||
}
|
||||
};
|
||||
|
||||
static struct dvb_usb_device_properties cxusb_mygica_d689_properties = {
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||
|
||||
.usb_ctrl = CYPRESS_FX2,
|
||||
|
||||
.size_of_priv = sizeof(struct cxusb_state),
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.streaming_ctrl = cxusb_d680_dmb_streaming_ctrl,
|
||||
.frontend_attach = cxusb_mygica_d689_frontend_attach,
|
||||
.tuner_attach = cxusb_mygica_d689_tuner_attach,
|
||||
|
||||
/* parameter for the MPEG2-data transfer */
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 5,
|
||||
.endpoint = 0x02,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 8192,
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
.power_ctrl = cxusb_d680_dmb_power_ctrl,
|
||||
|
||||
.i2c_algo = &cxusb_i2c_algo,
|
||||
|
||||
.generic_bulk_ctrl_endpoint = 0x01,
|
||||
|
||||
.rc_interval = 100,
|
||||
.rc_key_map = d680_dmb_rc_keys,
|
||||
.rc_key_map_size = ARRAY_SIZE(d680_dmb_rc_keys),
|
||||
.rc_query = cxusb_d680_dmb_rc_query,
|
||||
|
||||
.num_device_descs = 1,
|
||||
.devices = {
|
||||
{
|
||||
"Mygica D689 DMB-TH",
|
||||
{ NULL },
|
||||
{ &cxusb_table[19], NULL },
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
static struct usb_driver cxusb_driver = {
|
||||
.name = "dvb_usb_cxusb",
|
||||
.probe = cxusb_probe,
|
||||
|
|
|
|||
|
|
@ -558,8 +558,7 @@ static int dib0700_rc_query_legacy(struct dvb_usb_device *d, u32 *event,
|
|||
struct dib0700_rc_response {
|
||||
u8 report_id;
|
||||
u8 data_state;
|
||||
u8 system_msb;
|
||||
u8 system_lsb;
|
||||
u16 system;
|
||||
u8 data;
|
||||
u8 not_data;
|
||||
};
|
||||
|
|
@ -589,37 +588,50 @@ static int dib0700_rc_query_v1_20(struct dvb_usb_device *d, u32 *event,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (actlen != sizeof(buf)) {
|
||||
/* We didn't get back the 6 byte message we expected */
|
||||
err("Unexpected RC response size [%d]", actlen);
|
||||
return -1;
|
||||
|
||||
switch (dvb_usb_dib0700_ir_proto) {
|
||||
case 0:
|
||||
poll_reply.report_id = 0;
|
||||
poll_reply.data_state = 1;
|
||||
poll_reply.system = buf[2];
|
||||
poll_reply.data = buf[4];
|
||||
poll_reply.not_data = buf[5];
|
||||
|
||||
/* NEC protocol sends repeat code as 0 0 0 FF */
|
||||
if ((poll_reply.system == 0x00) && (poll_reply.data == 0x00)
|
||||
&& (poll_reply.not_data == 0xff)) {
|
||||
poll_reply.data_state = 2;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (actlen != sizeof(buf)) {
|
||||
/* We didn't get back the 6 byte message we expected */
|
||||
err("Unexpected RC response size [%d]", actlen);
|
||||
return -1;
|
||||
}
|
||||
|
||||
poll_reply.report_id = buf[0];
|
||||
poll_reply.data_state = buf[1];
|
||||
poll_reply.system = (buf[2] << 8) | buf[3];
|
||||
poll_reply.data = buf[4];
|
||||
poll_reply.not_data = buf[5];
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
poll_reply.report_id = buf[0];
|
||||
poll_reply.data_state = buf[1];
|
||||
poll_reply.system_msb = buf[2];
|
||||
poll_reply.system_lsb = buf[3];
|
||||
poll_reply.data = buf[4];
|
||||
poll_reply.not_data = buf[5];
|
||||
|
||||
/*
|
||||
info("rid=%02x ds=%02x sm=%02x sl=%02x d=%02x nd=%02x\n",
|
||||
poll_reply.report_id, poll_reply.data_state,
|
||||
poll_reply.system_msb, poll_reply.system_lsb,
|
||||
poll_reply.data, poll_reply.not_data);
|
||||
*/
|
||||
|
||||
if ((poll_reply.data + poll_reply.not_data) != 0xff) {
|
||||
/* Key failed integrity check */
|
||||
err("key failed integrity check: %02x %02x %02x %02x",
|
||||
poll_reply.system_msb, poll_reply.system_lsb,
|
||||
err("key failed integrity check: %04x %02x %02x",
|
||||
poll_reply.system,
|
||||
poll_reply.data, poll_reply.not_data);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* Find the key in the map */
|
||||
for (i = 0; i < d->props.rc_key_map_size; i++) {
|
||||
if (rc5_custom(&keymap[i]) == poll_reply.system_lsb &&
|
||||
if (rc5_custom(&keymap[i]) == (poll_reply.system & 0xff) &&
|
||||
rc5_data(&keymap[i]) == poll_reply.data) {
|
||||
*event = keymap[i].event;
|
||||
found = 1;
|
||||
|
|
@ -628,8 +640,8 @@ static int dib0700_rc_query_v1_20(struct dvb_usb_device *d, u32 *event,
|
|||
}
|
||||
|
||||
if (found == 0) {
|
||||
err("Unknown remote controller key: %02x %02x %02x %02x",
|
||||
poll_reply.system_msb, poll_reply.system_lsb,
|
||||
err("Unknown remote controller key: %04x %02x %02x",
|
||||
poll_reply.system,
|
||||
poll_reply.data, poll_reply.not_data);
|
||||
d->last_event = 0;
|
||||
return 0;
|
||||
|
|
@ -874,6 +886,49 @@ static struct dvb_usb_rc_key dib0700_rc_keys[] = {
|
|||
{ 0x1d37, KEY_RECORD },
|
||||
{ 0x1d3b, KEY_GOTO },
|
||||
{ 0x1d3d, KEY_POWER },
|
||||
|
||||
/* Key codes for the Pixelview SBTVD remote (proto NEC) */
|
||||
{ 0x8613, KEY_MUTE },
|
||||
{ 0x8612, KEY_POWER },
|
||||
{ 0x8601, KEY_1 },
|
||||
{ 0x8602, KEY_2 },
|
||||
{ 0x8603, KEY_3 },
|
||||
{ 0x8604, KEY_4 },
|
||||
{ 0x8605, KEY_5 },
|
||||
{ 0x8606, KEY_6 },
|
||||
{ 0x8607, KEY_7 },
|
||||
{ 0x8608, KEY_8 },
|
||||
{ 0x8609, KEY_9 },
|
||||
{ 0x8600, KEY_0 },
|
||||
{ 0x860d, KEY_CHANNELUP },
|
||||
{ 0x8619, KEY_CHANNELDOWN },
|
||||
{ 0x8610, KEY_VOLUMEUP },
|
||||
{ 0x860c, KEY_VOLUMEDOWN },
|
||||
|
||||
{ 0x860a, KEY_CAMERA },
|
||||
{ 0x860b, KEY_ZOOM },
|
||||
{ 0x861b, KEY_BACKSPACE },
|
||||
{ 0x8615, KEY_ENTER },
|
||||
|
||||
{ 0x861d, KEY_UP },
|
||||
{ 0x861e, KEY_DOWN },
|
||||
{ 0x860e, KEY_LEFT },
|
||||
{ 0x860f, KEY_RIGHT },
|
||||
|
||||
{ 0x8618, KEY_RECORD },
|
||||
{ 0x861a, KEY_STOP },
|
||||
|
||||
/* Key codes for the EvolutePC TVWay+ remote (proto NEC) */
|
||||
{ 0x7a00, KEY_MENU },
|
||||
{ 0x7a01, KEY_RECORD },
|
||||
{ 0x7a02, KEY_PLAY },
|
||||
{ 0x7a03, KEY_STOP },
|
||||
{ 0x7a10, KEY_CHANNELUP },
|
||||
{ 0x7a11, KEY_CHANNELDOWN },
|
||||
{ 0x7a12, KEY_VOLUMEUP },
|
||||
{ 0x7a13, KEY_VOLUMEDOWN },
|
||||
{ 0x7a40, KEY_POWER },
|
||||
{ 0x7a41, KEY_MUTE },
|
||||
};
|
||||
|
||||
/* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */
|
||||
|
|
@ -1133,6 +1188,7 @@ static struct dib0070_config dib7770p_dib0070_config = {
|
|||
.clock_khz = 12000,
|
||||
.clock_pad_drive = 0,
|
||||
.flip_chip = 1,
|
||||
.charge_pump = 2,
|
||||
};
|
||||
|
||||
static int dib7070_set_param_override(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
|
||||
|
|
@ -1209,6 +1265,16 @@ static int dib7070p_tuner_attach(struct dvb_usb_adapter *adap)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int stk70x0p_pid_filter(struct dvb_usb_adapter *adapter, int index, u16 pid, int onoff)
|
||||
{
|
||||
return dib7000p_pid_filter(adapter->fe, index, pid, onoff);
|
||||
}
|
||||
|
||||
static int stk70x0p_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff)
|
||||
{
|
||||
return dib7000p_pid_filter_ctrl(adapter->fe, onoff);
|
||||
}
|
||||
|
||||
static struct dibx000_bandwidth_config dib7070_bw_config_12_mhz = {
|
||||
60000, 15000, // internal, sampling
|
||||
1, 20, 3, 1, 0, // pll_cfg: prediv, ratio, range, reset, bypass
|
||||
|
|
@ -1500,6 +1566,15 @@ static int dib807x_tuner_attach(struct dvb_usb_adapter *adap)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int stk807x_pid_filter(struct dvb_usb_adapter *adapter, int index, u16 pid, int onoff)
|
||||
{
|
||||
return dib8000_pid_filter(adapter->fe, index, pid, onoff);
|
||||
}
|
||||
|
||||
static int stk807x_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff)
|
||||
{
|
||||
return dib8000_pid_filter_ctrl(adapter->fe, onoff);
|
||||
}
|
||||
|
||||
/* STK807x */
|
||||
static int stk807x_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
|
|
@ -1861,6 +1936,7 @@ struct usb_device_id dib0700_usb_id_table[] = {
|
|||
{ USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK807XPVR) },
|
||||
{ USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK807XP) },
|
||||
{ USB_DEVICE(USB_VID_PIXELVIEW, USB_PID_PIXELVIEW_SBTVD) },
|
||||
{ USB_DEVICE(USB_VID_EVOLUTEPC, USB_PID_TVWAY_PLUS) },
|
||||
{ 0 } /* Terminating entry */
|
||||
};
|
||||
MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
|
||||
|
|
@ -1895,6 +1971,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
|
|||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
|
||||
.pid_filter_count = 32,
|
||||
.pid_filter = stk70x0p_pid_filter,
|
||||
.pid_filter_ctrl = stk70x0p_pid_filter_ctrl,
|
||||
.frontend_attach = stk7700p_frontend_attach,
|
||||
.tuner_attach = stk7700p_tuner_attach,
|
||||
|
||||
|
|
@ -1976,11 +2056,19 @@ struct dvb_usb_device_properties dib0700_devices[] = {
|
|||
.num_adapters = 2,
|
||||
.adapter = {
|
||||
{
|
||||
.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
|
||||
.pid_filter_count = 32,
|
||||
.pid_filter = stk70x0p_pid_filter,
|
||||
.pid_filter_ctrl = stk70x0p_pid_filter_ctrl,
|
||||
.frontend_attach = stk7700d_frontend_attach,
|
||||
.tuner_attach = stk7700d_tuner_attach,
|
||||
|
||||
DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
|
||||
}, {
|
||||
.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
|
||||
.pid_filter_count = 32,
|
||||
.pid_filter = stk70x0p_pid_filter,
|
||||
.pid_filter_ctrl = stk70x0p_pid_filter_ctrl,
|
||||
.frontend_attach = stk7700d_frontend_attach,
|
||||
.tuner_attach = stk7700d_tuner_attach,
|
||||
|
||||
|
|
@ -2023,6 +2111,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
|
|||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
|
||||
.pid_filter_count = 32,
|
||||
.pid_filter = stk70x0p_pid_filter,
|
||||
.pid_filter_ctrl = stk70x0p_pid_filter_ctrl,
|
||||
.frontend_attach = stk7700P2_frontend_attach,
|
||||
.tuner_attach = stk7700d_tuner_attach,
|
||||
|
||||
|
|
@ -2055,6 +2147,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
|
|||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
|
||||
.pid_filter_count = 32,
|
||||
.pid_filter = stk70x0p_pid_filter,
|
||||
.pid_filter_ctrl = stk70x0p_pid_filter_ctrl,
|
||||
.frontend_attach = stk7070p_frontend_attach,
|
||||
.tuner_attach = dib7070p_tuner_attach,
|
||||
|
||||
|
|
@ -2122,6 +2218,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
|
|||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
|
||||
.pid_filter_count = 32,
|
||||
.pid_filter = stk70x0p_pid_filter,
|
||||
.pid_filter_ctrl = stk70x0p_pid_filter_ctrl,
|
||||
.frontend_attach = stk7070p_frontend_attach,
|
||||
.tuner_attach = dib7070p_tuner_attach,
|
||||
|
||||
|
|
@ -2157,6 +2257,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
|
|||
.num_adapters = 2,
|
||||
.adapter = {
|
||||
{
|
||||
.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
|
||||
.pid_filter_count = 32,
|
||||
.pid_filter = stk70x0p_pid_filter,
|
||||
.pid_filter_ctrl = stk70x0p_pid_filter_ctrl,
|
||||
.frontend_attach = stk7070pd_frontend_attach0,
|
||||
.tuner_attach = dib7070p_tuner_attach,
|
||||
|
||||
|
|
@ -2164,6 +2268,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
|
|||
|
||||
.size_of_priv = sizeof(struct dib0700_adapter_state),
|
||||
}, {
|
||||
.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
|
||||
.pid_filter_count = 32,
|
||||
.pid_filter = stk70x0p_pid_filter,
|
||||
.pid_filter_ctrl = stk70x0p_pid_filter_ctrl,
|
||||
.frontend_attach = stk7070pd_frontend_attach1,
|
||||
.tuner_attach = dib7070p_tuner_attach,
|
||||
|
||||
|
|
@ -2210,6 +2318,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
|
|||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
|
||||
.pid_filter_count = 32,
|
||||
.pid_filter = stk70x0p_pid_filter,
|
||||
.pid_filter_ctrl = stk70x0p_pid_filter_ctrl,
|
||||
.frontend_attach = stk7700ph_frontend_attach,
|
||||
.tuner_attach = stk7700ph_tuner_attach,
|
||||
|
||||
|
|
@ -2322,6 +2434,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
|
|||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
|
||||
.pid_filter_count = 32,
|
||||
.pid_filter = stk70x0p_pid_filter,
|
||||
.pid_filter_ctrl = stk70x0p_pid_filter_ctrl,
|
||||
.frontend_attach = stk7070p_frontend_attach,
|
||||
.tuner_attach = dib7770p_tuner_attach,
|
||||
|
||||
|
|
@ -2353,6 +2469,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
|
|||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
|
||||
.pid_filter_count = 32,
|
||||
.pid_filter = stk807x_pid_filter,
|
||||
.pid_filter_ctrl = stk807x_pid_filter_ctrl,
|
||||
.frontend_attach = stk807x_frontend_attach,
|
||||
.tuner_attach = dib807x_tuner_attach,
|
||||
|
||||
|
|
@ -2363,7 +2483,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
|
|||
},
|
||||
},
|
||||
|
||||
.num_device_descs = 2,
|
||||
.num_device_descs = 3,
|
||||
.devices = {
|
||||
{ "DiBcom STK807xP reference design",
|
||||
{ &dib0700_usb_id_table[62], NULL },
|
||||
|
|
@ -2373,6 +2493,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
|
|||
{ &dib0700_usb_id_table[63], NULL },
|
||||
{ NULL },
|
||||
},
|
||||
{ "EvolutePC TVWay+",
|
||||
{ &dib0700_usb_id_table[64], NULL },
|
||||
{ NULL },
|
||||
},
|
||||
},
|
||||
|
||||
.rc_interval = DEFAULT_RC_INTERVAL,
|
||||
|
|
@ -2384,6 +2508,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
|
|||
.num_adapters = 2,
|
||||
.adapter = {
|
||||
{
|
||||
.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
|
||||
.pid_filter_count = 32,
|
||||
.pid_filter = stk807x_pid_filter,
|
||||
.pid_filter_ctrl = stk807x_pid_filter_ctrl,
|
||||
.frontend_attach = stk807xpvr_frontend_attach0,
|
||||
.tuner_attach = dib807x_tuner_attach,
|
||||
|
||||
|
|
@ -2393,6 +2521,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
|
|||
sizeof(struct dib0700_adapter_state),
|
||||
},
|
||||
{
|
||||
.caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
|
||||
.pid_filter_count = 32,
|
||||
.pid_filter = stk807x_pid_filter,
|
||||
.pid_filter_ctrl = stk807x_pid_filter_ctrl,
|
||||
.frontend_attach = stk807xpvr_frontend_attach1,
|
||||
.tuner_attach = dib807x_tuner_attach,
|
||||
|
||||
|
|
|
|||
|
|
@ -88,6 +88,7 @@ int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap, short *adapter_nums)
|
|||
goto err;
|
||||
}
|
||||
adap->dvb_adap.priv = adap;
|
||||
adap->dvb_adap.fe_ioctl_override = adap->props.fe_ioctl_override;
|
||||
|
||||
if (adap->dev->props.read_mac_address) {
|
||||
if (adap->dev->props.read_mac_address(adap->dev,adap->dvb_adap.proposed_mac) == 0)
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#define USB_VID_DIBCOM 0x10b8
|
||||
#define USB_VID_DPOSH 0x1498
|
||||
#define USB_VID_DVICO 0x0fe9
|
||||
#define USB_VID_E3C 0x18b4
|
||||
#define USB_VID_ELGATO 0x0fd9
|
||||
#define USB_VID_EMPIA 0xeb1a
|
||||
#define USB_VID_GENPIX 0x09c0
|
||||
|
|
@ -61,6 +62,7 @@
|
|||
#define USB_VID_XTENSIONS 0x1ae7
|
||||
#define USB_VID_HUMAX_COEX 0x10b9
|
||||
#define USB_VID_774 0x7a69
|
||||
#define USB_VID_EVOLUTEPC 0x1e59
|
||||
|
||||
/* Product IDs */
|
||||
#define USB_PID_ADSTECH_USB2_COLD 0xa333
|
||||
|
|
@ -103,6 +105,11 @@
|
|||
#define USB_PID_DIBCOM_STK7770P 0x1e80
|
||||
#define USB_PID_DPOSH_M9206_COLD 0x9206
|
||||
#define USB_PID_DPOSH_M9206_WARM 0xa090
|
||||
#define USB_PID_E3C_EC168 0x1689
|
||||
#define USB_PID_E3C_EC168_2 0xfffa
|
||||
#define USB_PID_E3C_EC168_3 0xfffb
|
||||
#define USB_PID_E3C_EC168_4 0x1001
|
||||
#define USB_PID_E3C_EC168_5 0x1002
|
||||
#define USB_PID_UNIWILL_STK7700P 0x6003
|
||||
#define USB_PID_GENIUS_TVGO_DVB_T03 0x4012
|
||||
#define USB_PID_GRANDTEC_DVBT_USB_COLD 0x0fa0
|
||||
|
|
@ -115,6 +122,7 @@
|
|||
#define USB_PID_KWORLD_395U_3 0xe395
|
||||
#define USB_PID_KWORLD_MC810 0xc810
|
||||
#define USB_PID_KWORLD_PC160_2T 0xc160
|
||||
#define USB_PID_KWORLD_PC160_T 0xc161
|
||||
#define USB_PID_KWORLD_VSTREAM_COLD 0x17de
|
||||
#define USB_PID_KWORLD_VSTREAM_WARM 0x17df
|
||||
#define USB_PID_TERRATEC_CINERGY_T_USB_XE 0x0055
|
||||
|
|
@ -271,10 +279,13 @@
|
|||
#define USB_PID_TELESTAR_STARSTICK_2 0x8000
|
||||
#define USB_PID_MSI_DIGI_VOX_MINI_III 0x8807
|
||||
#define USB_PID_SONY_PLAYTV 0x0003
|
||||
#define USB_PID_MYGICA_D689 0xd811
|
||||
#define USB_PID_ELGATO_EYETV_DTT 0x0021
|
||||
#define USB_PID_ELGATO_EYETV_DTT_Dlx 0x0020
|
||||
#define USB_PID_DVB_T_USB_STICK_HIGH_SPEED_COLD 0x5000
|
||||
#define USB_PID_DVB_T_USB_STICK_HIGH_SPEED_WARM 0x5001
|
||||
#define USB_PID_FRIIO_WHITE 0x0001
|
||||
#define USB_PID_TVWAY_PLUS 0x0002
|
||||
#define USB_PID_SVEON_STV20 0xe39d
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -162,6 +162,9 @@ struct dvb_usb_adapter_properties {
|
|||
struct usb_data_stream_properties stream;
|
||||
|
||||
int size_of_priv;
|
||||
|
||||
int (*fe_ioctl_override) (struct dvb_frontend *,
|
||||
unsigned int, void *, unsigned int);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
440
drivers/media/dvb/dvb-usb/ec168.c
Normal file
440
drivers/media/dvb/dvb-usb/ec168.c
Normal file
|
|
@ -0,0 +1,440 @@
|
|||
/*
|
||||
* E3C EC168 DVB USB driver
|
||||
*
|
||||
* Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
|
||||
*
|
||||
* 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 "ec168.h"
|
||||
#include "ec100.h"
|
||||
#include "mxl5005s.h"
|
||||
|
||||
/* debug */
|
||||
static int dvb_usb_ec168_debug;
|
||||
module_param_named(debug, dvb_usb_ec168_debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
|
||||
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
||||
|
||||
static struct ec100_config ec168_ec100_config;
|
||||
|
||||
static int ec168_rw_udev(struct usb_device *udev, struct ec168_req *req)
|
||||
{
|
||||
int ret;
|
||||
unsigned int pipe;
|
||||
u8 request, requesttype;
|
||||
u8 buf[req->size];
|
||||
|
||||
switch (req->cmd) {
|
||||
case DOWNLOAD_FIRMWARE:
|
||||
case GPIO:
|
||||
case WRITE_I2C:
|
||||
case STREAMING_CTRL:
|
||||
requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT);
|
||||
request = req->cmd;
|
||||
break;
|
||||
case READ_I2C:
|
||||
requesttype = (USB_TYPE_VENDOR | USB_DIR_IN);
|
||||
request = req->cmd;
|
||||
break;
|
||||
case GET_CONFIG:
|
||||
requesttype = (USB_TYPE_VENDOR | USB_DIR_IN);
|
||||
request = CONFIG;
|
||||
break;
|
||||
case SET_CONFIG:
|
||||
requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT);
|
||||
request = CONFIG;
|
||||
break;
|
||||
case WRITE_DEMOD:
|
||||
requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT);
|
||||
request = DEMOD_RW;
|
||||
break;
|
||||
case READ_DEMOD:
|
||||
requesttype = (USB_TYPE_VENDOR | USB_DIR_IN);
|
||||
request = DEMOD_RW;
|
||||
break;
|
||||
default:
|
||||
err("unknown command:%02x", req->cmd);
|
||||
ret = -EPERM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (requesttype == (USB_TYPE_VENDOR | USB_DIR_OUT)) {
|
||||
/* write */
|
||||
memcpy(buf, req->data, req->size);
|
||||
pipe = usb_sndctrlpipe(udev, 0);
|
||||
} else {
|
||||
/* read */
|
||||
pipe = usb_rcvctrlpipe(udev, 0);
|
||||
}
|
||||
|
||||
msleep(1); /* avoid I2C errors */
|
||||
|
||||
ret = usb_control_msg(udev, pipe, request, requesttype, req->value,
|
||||
req->index, buf, sizeof(buf), EC168_USB_TIMEOUT);
|
||||
|
||||
ec168_debug_dump(request, requesttype, req->value, req->index, buf,
|
||||
req->size, deb_xfer);
|
||||
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
else
|
||||
ret = 0;
|
||||
|
||||
/* read request, copy returned data to return buf */
|
||||
if (!ret && requesttype == (USB_TYPE_VENDOR | USB_DIR_IN))
|
||||
memcpy(req->data, buf, req->size);
|
||||
|
||||
return ret;
|
||||
error:
|
||||
deb_info("%s: failed:%d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ec168_ctrl_msg(struct dvb_usb_device *d, struct ec168_req *req)
|
||||
{
|
||||
return ec168_rw_udev(d->udev, req);
|
||||
}
|
||||
|
||||
/* I2C */
|
||||
static int ec168_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
|
||||
int num)
|
||||
{
|
||||
struct dvb_usb_device *d = i2c_get_adapdata(adap);
|
||||
struct ec168_req req;
|
||||
int i = 0;
|
||||
int ret;
|
||||
|
||||
if (num > 2)
|
||||
return -EINVAL;
|
||||
|
||||
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
|
||||
return -EAGAIN;
|
||||
|
||||
while (i < num) {
|
||||
if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
|
||||
if (msg[i].addr == ec168_ec100_config.demod_address) {
|
||||
req.cmd = READ_DEMOD;
|
||||
req.value = 0;
|
||||
req.index = 0xff00 + msg[i].buf[0]; /* reg */
|
||||
req.size = msg[i+1].len; /* bytes to read */
|
||||
req.data = &msg[i+1].buf[0];
|
||||
ret = ec168_ctrl_msg(d, &req);
|
||||
i += 2;
|
||||
} else {
|
||||
err("I2C read not implemented");
|
||||
ret = -ENOSYS;
|
||||
i += 2;
|
||||
}
|
||||
} else {
|
||||
if (msg[i].addr == ec168_ec100_config.demod_address) {
|
||||
req.cmd = WRITE_DEMOD;
|
||||
req.value = msg[i].buf[1]; /* val */
|
||||
req.index = 0xff00 + msg[i].buf[0]; /* reg */
|
||||
req.size = 0;
|
||||
req.data = NULL;
|
||||
ret = ec168_ctrl_msg(d, &req);
|
||||
i += 1;
|
||||
} else {
|
||||
req.cmd = WRITE_I2C;
|
||||
req.value = msg[i].buf[0]; /* val */
|
||||
req.index = 0x0100 + msg[i].addr; /* I2C addr */
|
||||
req.size = msg[i].len-1;
|
||||
req.data = &msg[i].buf[1];
|
||||
ret = ec168_ctrl_msg(d, &req);
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
}
|
||||
ret = i;
|
||||
|
||||
error:
|
||||
mutex_unlock(&d->i2c_mutex);
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
static u32 ec168_i2c_func(struct i2c_adapter *adapter)
|
||||
{
|
||||
return I2C_FUNC_I2C;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm ec168_i2c_algo = {
|
||||
.master_xfer = ec168_i2c_xfer,
|
||||
.functionality = ec168_i2c_func,
|
||||
};
|
||||
|
||||
/* Callbacks for DVB USB */
|
||||
static struct ec100_config ec168_ec100_config = {
|
||||
.demod_address = 0xff, /* not real address, demod is integrated */
|
||||
};
|
||||
|
||||
static int ec168_ec100_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
deb_info("%s:\n", __func__);
|
||||
adap->fe = dvb_attach(ec100_attach, &ec168_ec100_config,
|
||||
&adap->dev->i2c_adap);
|
||||
if (adap->fe == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct mxl5005s_config ec168_mxl5003s_config = {
|
||||
.i2c_address = 0xc6,
|
||||
.if_freq = IF_FREQ_4570000HZ,
|
||||
.xtal_freq = CRYSTAL_FREQ_16000000HZ,
|
||||
.agc_mode = MXL_SINGLE_AGC,
|
||||
.tracking_filter = MXL_TF_OFF,
|
||||
.rssi_enable = MXL_RSSI_ENABLE,
|
||||
.cap_select = MXL_CAP_SEL_ENABLE,
|
||||
.div_out = MXL_DIV_OUT_4,
|
||||
.clock_out = MXL_CLOCK_OUT_DISABLE,
|
||||
.output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
|
||||
.top = MXL5005S_TOP_25P2,
|
||||
.mod_mode = MXL_DIGITAL_MODE,
|
||||
.if_mode = MXL_ZERO_IF,
|
||||
.AgcMasterByte = 0x00,
|
||||
};
|
||||
|
||||
static int ec168_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
deb_info("%s:\n", __func__);
|
||||
return dvb_attach(mxl5005s_attach, adap->fe, &adap->dev->i2c_adap,
|
||||
&ec168_mxl5003s_config) == NULL ? -ENODEV : 0;
|
||||
}
|
||||
|
||||
static int ec168_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
|
||||
{
|
||||
struct ec168_req req = {STREAMING_CTRL, 0x7f01, 0x0202, 0, NULL};
|
||||
deb_info("%s: onoff:%d\n", __func__, onoff);
|
||||
if (onoff)
|
||||
req.index = 0x0102;
|
||||
return ec168_ctrl_msg(adap->dev, &req);
|
||||
}
|
||||
|
||||
static int ec168_download_firmware(struct usb_device *udev,
|
||||
const struct firmware *fw)
|
||||
{
|
||||
int i, len, packets, remainder, ret;
|
||||
u16 addr = 0x0000; /* firmware start address */
|
||||
struct ec168_req req = {DOWNLOAD_FIRMWARE, 0, 0, 0, NULL};
|
||||
deb_info("%s:\n", __func__);
|
||||
|
||||
#define FW_PACKET_MAX_DATA 2048
|
||||
packets = fw->size / FW_PACKET_MAX_DATA;
|
||||
remainder = fw->size % FW_PACKET_MAX_DATA;
|
||||
len = FW_PACKET_MAX_DATA;
|
||||
for (i = 0; i <= packets; i++) {
|
||||
if (i == packets) /* set size of the last packet */
|
||||
len = remainder;
|
||||
|
||||
req.size = len;
|
||||
req.data = (u8 *)(fw->data + i * FW_PACKET_MAX_DATA);
|
||||
req.index = addr;
|
||||
addr += FW_PACKET_MAX_DATA;
|
||||
|
||||
ret = ec168_rw_udev(udev, &req);
|
||||
if (ret) {
|
||||
err("firmware download failed:%d packet:%d", ret, i);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
req.size = 0;
|
||||
|
||||
/* set "warm"? */
|
||||
req.cmd = SET_CONFIG;
|
||||
req.value = 0;
|
||||
req.index = 0x0001;
|
||||
ret = ec168_rw_udev(udev, &req);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
/* really needed - no idea what does */
|
||||
req.cmd = GPIO;
|
||||
req.value = 0;
|
||||
req.index = 0x0206;
|
||||
ret = ec168_rw_udev(udev, &req);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
/* activate tuner I2C? */
|
||||
req.cmd = WRITE_I2C;
|
||||
req.value = 0;
|
||||
req.index = 0x00c6;
|
||||
ret = ec168_rw_udev(udev, &req);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
return ret;
|
||||
error:
|
||||
deb_info("%s: failed:%d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ec168_identify_state(struct usb_device *udev,
|
||||
struct dvb_usb_device_properties *props,
|
||||
struct dvb_usb_device_description **desc, int *cold)
|
||||
{
|
||||
int ret;
|
||||
u8 reply;
|
||||
struct ec168_req req = {GET_CONFIG, 0, 1, sizeof(reply), &reply};
|
||||
deb_info("%s:\n", __func__);
|
||||
|
||||
ret = ec168_rw_udev(udev, &req);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
deb_info("%s: reply:%02x\n", __func__, reply);
|
||||
|
||||
if (reply == 0x01)
|
||||
*cold = 0;
|
||||
else
|
||||
*cold = 1;
|
||||
|
||||
return ret;
|
||||
error:
|
||||
deb_info("%s: failed:%d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* DVB USB Driver stuff */
|
||||
static struct dvb_usb_device_properties ec168_properties;
|
||||
|
||||
static int ec168_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
int ret;
|
||||
deb_info("%s: interface:%d\n", __func__,
|
||||
intf->cur_altsetting->desc.bInterfaceNumber);
|
||||
|
||||
ret = dvb_usb_device_init(intf, &ec168_properties, THIS_MODULE, NULL,
|
||||
adapter_nr);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
return ret;
|
||||
error:
|
||||
deb_info("%s: failed:%d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define E3C_EC168_1689 0
|
||||
#define E3C_EC168_FFFA 1
|
||||
#define E3C_EC168_FFFB 2
|
||||
#define E3C_EC168_1001 3
|
||||
#define E3C_EC168_1002 4
|
||||
|
||||
static struct usb_device_id ec168_id[] = {
|
||||
[E3C_EC168_1689] =
|
||||
{USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168)},
|
||||
[E3C_EC168_FFFA] =
|
||||
{USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_2)},
|
||||
[E3C_EC168_FFFB] =
|
||||
{USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_3)},
|
||||
[E3C_EC168_1001] =
|
||||
{USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_4)},
|
||||
[E3C_EC168_1002] =
|
||||
{USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_5)},
|
||||
{} /* terminating entry */
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(usb, ec168_id);
|
||||
|
||||
static struct dvb_usb_device_properties ec168_properties = {
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||
|
||||
.usb_ctrl = DEVICE_SPECIFIC,
|
||||
.download_firmware = ec168_download_firmware,
|
||||
.firmware = "dvb-usb-ec168.fw",
|
||||
.no_reconnect = 1,
|
||||
|
||||
.size_of_priv = 0,
|
||||
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.streaming_ctrl = ec168_streaming_ctrl,
|
||||
.frontend_attach = ec168_ec100_frontend_attach,
|
||||
.tuner_attach = ec168_mxl5003s_tuner_attach,
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 6,
|
||||
.endpoint = 0x82,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = (32*512),
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
.identify_state = ec168_identify_state,
|
||||
|
||||
.i2c_algo = &ec168_i2c_algo,
|
||||
|
||||
.num_device_descs = 1,
|
||||
.devices = {
|
||||
{
|
||||
.name = "E3C EC168 DVB-T USB2.0 reference design",
|
||||
.cold_ids = {
|
||||
&ec168_id[E3C_EC168_1689],
|
||||
&ec168_id[E3C_EC168_FFFA],
|
||||
&ec168_id[E3C_EC168_FFFB],
|
||||
&ec168_id[E3C_EC168_1001],
|
||||
&ec168_id[E3C_EC168_1002],
|
||||
NULL},
|
||||
.warm_ids = {NULL},
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
static struct usb_driver ec168_driver = {
|
||||
.name = "dvb_usb_ec168",
|
||||
.probe = ec168_probe,
|
||||
.disconnect = dvb_usb_device_exit,
|
||||
.id_table = ec168_id,
|
||||
};
|
||||
|
||||
/* module stuff */
|
||||
static int __init ec168_module_init(void)
|
||||
{
|
||||
int ret;
|
||||
deb_info("%s:\n", __func__);
|
||||
ret = usb_register(&ec168_driver);
|
||||
if (ret)
|
||||
err("module init failed:%d", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit ec168_module_exit(void)
|
||||
{
|
||||
deb_info("%s:\n", __func__);
|
||||
/* deregister this driver from the USB subsystem */
|
||||
usb_deregister(&ec168_driver);
|
||||
}
|
||||
|
||||
module_init(ec168_module_init);
|
||||
module_exit(ec168_module_exit);
|
||||
|
||||
MODULE_AUTHOR("Antti Palosaari <[email protected]>");
|
||||
MODULE_DESCRIPTION("E3C EC168 DVB-T USB2.0 driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
73
drivers/media/dvb/dvb-usb/ec168.h
Normal file
73
drivers/media/dvb/dvb-usb/ec168.h
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* E3C EC168 DVB USB driver
|
||||
*
|
||||
* Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef EC168_H
|
||||
#define EC168_H
|
||||
|
||||
#define DVB_USB_LOG_PREFIX "ec168"
|
||||
#include "dvb-usb.h"
|
||||
|
||||
#define deb_info(args...) dprintk(dvb_usb_ec168_debug, 0x01, args)
|
||||
#define deb_rc(args...) dprintk(dvb_usb_ec168_debug, 0x02, args)
|
||||
#define deb_xfer(args...) dprintk(dvb_usb_ec168_debug, 0x04, args)
|
||||
#define deb_reg(args...) dprintk(dvb_usb_ec168_debug, 0x08, args)
|
||||
#define deb_i2c(args...) dprintk(dvb_usb_ec168_debug, 0x10, args)
|
||||
#define deb_fw(args...) dprintk(dvb_usb_ec168_debug, 0x20, args)
|
||||
|
||||
#define ec168_debug_dump(r, t, v, i, b, l, func) { \
|
||||
int loop_; \
|
||||
func("%02x %02x %02x %02x %02x %02x %02x %02x", \
|
||||
t, r, v & 0xff, v >> 8, i & 0xff, i >> 8, l & 0xff, l >> 8); \
|
||||
if (t == (USB_TYPE_VENDOR | USB_DIR_OUT)) \
|
||||
func(" >>> "); \
|
||||
else \
|
||||
func(" <<< "); \
|
||||
for (loop_ = 0; loop_ < l; loop_++) \
|
||||
func("%02x ", b[loop_]); \
|
||||
func("\n");\
|
||||
}
|
||||
|
||||
#define EC168_USB_TIMEOUT 1000
|
||||
|
||||
struct ec168_req {
|
||||
u8 cmd; /* [1] */
|
||||
u16 value; /* [2|3] */
|
||||
u16 index; /* [4|5] */
|
||||
u16 size; /* [6|7] */
|
||||
u8 *data;
|
||||
};
|
||||
|
||||
enum ec168_cmd {
|
||||
DOWNLOAD_FIRMWARE = 0x00,
|
||||
CONFIG = 0x01,
|
||||
DEMOD_RW = 0x03,
|
||||
GPIO = 0x04,
|
||||
STREAMING_CTRL = 0x10,
|
||||
READ_I2C = 0x20,
|
||||
WRITE_I2C = 0x21,
|
||||
HID_DOWNLOAD = 0x30,
|
||||
GET_CONFIG,
|
||||
SET_CONFIG,
|
||||
READ_DEMOD,
|
||||
WRITE_DEMOD,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -232,12 +232,6 @@ static int jdvbt90502_read_status(struct dvb_frontend *fe, fe_status_t *state)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int jdvbt90502_read_ber(struct dvb_frontend *fe, u32 *ber)
|
||||
{
|
||||
*ber = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int jdvbt90502_read_signal_strength(struct dvb_frontend *fe,
|
||||
u16 *strength)
|
||||
{
|
||||
|
|
@ -264,26 +258,26 @@ static int jdvbt90502_read_signal_strength(struct dvb_frontend *fe,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int jdvbt90502_read_snr(struct dvb_frontend *fe, u16 *snr)
|
||||
{
|
||||
*snr = 0x0101;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int jdvbt90502_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
|
||||
/* filter out un-supported properties to notify users */
|
||||
static int jdvbt90502_set_property(struct dvb_frontend *fe,
|
||||
struct dtv_property *tvp)
|
||||
{
|
||||
*ucblocks = 0;
|
||||
return 0;
|
||||
}
|
||||
int r = 0;
|
||||
|
||||
static int jdvbt90502_get_tune_settings(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_tune_settings *fs)
|
||||
{
|
||||
fs->min_delay_ms = 500;
|
||||
fs->step_size = 0;
|
||||
fs->max_drift = 0;
|
||||
|
||||
return 0;
|
||||
switch (tvp->cmd) {
|
||||
case DTV_DELIVERY_SYSTEM:
|
||||
if (tvp->u.data != SYS_ISDBT)
|
||||
r = -EINVAL;
|
||||
break;
|
||||
case DTV_CLEAR:
|
||||
case DTV_TUNE:
|
||||
case DTV_FREQUENCY:
|
||||
break;
|
||||
default:
|
||||
r = -EINVAL;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static int jdvbt90502_get_frontend(struct dvb_frontend *fe,
|
||||
|
|
@ -314,6 +308,9 @@ static int jdvbt90502_set_frontend(struct dvb_frontend *fe,
|
|||
|
||||
deb_fe("%s: Freq:%d\n", __func__, p->frequency);
|
||||
|
||||
/* for recovery from DTV_CLEAN */
|
||||
fe->dtv_property_cache.delivery_system = SYS_ISDBT;
|
||||
|
||||
ret = jdvbt90502_pll_set_freq(state, p->frequency);
|
||||
if (ret) {
|
||||
deb_fe("%s:ret == %d\n", __func__, ret);
|
||||
|
|
@ -323,12 +320,6 @@ static int jdvbt90502_set_frontend(struct dvb_frontend *fe,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int jdvbt90502_sleep(struct dvb_frontend *fe)
|
||||
{
|
||||
deb_fe("%s called.\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* (reg, val) commad list to initialize this module.
|
||||
|
|
@ -394,6 +385,7 @@ static int jdvbt90502_init(struct dvb_frontend *fe)
|
|||
if (ret != 1)
|
||||
goto error;
|
||||
}
|
||||
fe->dtv_property_cache.delivery_system = SYS_ISDBT;
|
||||
msleep(100);
|
||||
|
||||
return 0;
|
||||
|
|
@ -468,16 +460,13 @@ static struct dvb_frontend_ops jdvbt90502_ops = {
|
|||
.release = jdvbt90502_release,
|
||||
|
||||
.init = jdvbt90502_init,
|
||||
.sleep = jdvbt90502_sleep,
|
||||
.write = _jdvbt90502_write,
|
||||
|
||||
.set_property = jdvbt90502_set_property,
|
||||
|
||||
.set_frontend = jdvbt90502_set_frontend,
|
||||
.get_frontend = jdvbt90502_get_frontend,
|
||||
.get_tune_settings = jdvbt90502_get_tune_settings,
|
||||
|
||||
.read_status = jdvbt90502_read_status,
|
||||
.read_ber = jdvbt90502_read_ber,
|
||||
.read_signal_strength = jdvbt90502_read_signal_strength,
|
||||
.read_snr = jdvbt90502_read_snr,
|
||||
.read_ucblocks = jdvbt90502_read_ucblocks,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
config DVB_FIREDTV
|
||||
tristate "FireDTV and FloppyDTV"
|
||||
depends on DVB_CORE && IEEE1394
|
||||
depends on DVB_CORE && (FIREWIRE || IEEE1394)
|
||||
help
|
||||
Support for DVB receivers from Digital Everywhere
|
||||
which are connected via IEEE 1394 (FireWire).
|
||||
|
|
@ -13,8 +13,11 @@ config DVB_FIREDTV
|
|||
|
||||
if DVB_FIREDTV
|
||||
|
||||
config DVB_FIREDTV_FIREWIRE
|
||||
def_bool FIREWIRE = y || (FIREWIRE = m && DVB_FIREDTV = m)
|
||||
|
||||
config DVB_FIREDTV_IEEE1394
|
||||
def_bool IEEE1394
|
||||
def_bool IEEE1394 = y || (IEEE1394 = m && DVB_FIREDTV = m)
|
||||
|
||||
config DVB_FIREDTV_INPUT
|
||||
def_bool INPUT = y || (INPUT = m && DVB_FIREDTV = m)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
obj-$(CONFIG_DVB_FIREDTV) += firedtv.o
|
||||
|
||||
firedtv-y := firedtv-avc.o firedtv-ci.o firedtv-dvb.o firedtv-fe.o
|
||||
firedtv-$(CONFIG_DVB_FIREDTV_FIREWIRE) += firedtv-fw.o
|
||||
firedtv-$(CONFIG_DVB_FIREDTV_IEEE1394) += firedtv-1394.o
|
||||
firedtv-$(CONFIG_DVB_FIREDTV_INPUT) += firedtv-rc.o
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* FireDTV driver (formerly known as FireSAT)
|
||||
* FireDTV driver -- ieee1394 I/O backend
|
||||
*
|
||||
* Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com>
|
||||
* Copyright (C) 2007-2008 Ben Backx <ben@bbackx.com>
|
||||
|
|
@ -26,13 +26,16 @@
|
|||
#include <iso.h>
|
||||
#include <nodemgr.h>
|
||||
|
||||
#include <dvb_demux.h>
|
||||
|
||||
#include "firedtv.h"
|
||||
|
||||
static LIST_HEAD(node_list);
|
||||
static DEFINE_SPINLOCK(node_list_lock);
|
||||
|
||||
#define FIREWIRE_HEADER_SIZE 4
|
||||
#define CIP_HEADER_SIZE 8
|
||||
#define CIP_HEADER_SIZE 8
|
||||
#define MPEG2_TS_HEADER_SIZE 4
|
||||
#define MPEG2_TS_SOURCE_PACKET_SIZE (4 + 188)
|
||||
|
||||
static void rawiso_activity_cb(struct hpsb_iso *iso)
|
||||
{
|
||||
|
|
@ -62,20 +65,20 @@ static void rawiso_activity_cb(struct hpsb_iso *iso)
|
|||
buf = dma_region_i(&iso->data_buf, unsigned char,
|
||||
iso->infos[packet].offset + CIP_HEADER_SIZE);
|
||||
count = (iso->infos[packet].len - CIP_HEADER_SIZE) /
|
||||
(188 + FIREWIRE_HEADER_SIZE);
|
||||
MPEG2_TS_SOURCE_PACKET_SIZE;
|
||||
|
||||
/* ignore empty packet */
|
||||
if (iso->infos[packet].len <= CIP_HEADER_SIZE)
|
||||
continue;
|
||||
|
||||
while (count--) {
|
||||
if (buf[FIREWIRE_HEADER_SIZE] == 0x47)
|
||||
if (buf[MPEG2_TS_HEADER_SIZE] == 0x47)
|
||||
dvb_dmx_swfilter_packets(&fdtv->demux,
|
||||
&buf[FIREWIRE_HEADER_SIZE], 1);
|
||||
&buf[MPEG2_TS_HEADER_SIZE], 1);
|
||||
else
|
||||
dev_err(fdtv->device,
|
||||
"skipping invalid packet\n");
|
||||
buf += 188 + FIREWIRE_HEADER_SIZE;
|
||||
buf += MPEG2_TS_SOURCE_PACKET_SIZE;
|
||||
}
|
||||
}
|
||||
out:
|
||||
|
|
@ -87,15 +90,20 @@ static inline struct node_entry *node_of(struct firedtv *fdtv)
|
|||
return container_of(fdtv->device, struct unit_directory, device)->ne;
|
||||
}
|
||||
|
||||
static int node_lock(struct firedtv *fdtv, u64 addr, void *data, __be32 arg)
|
||||
static int node_lock(struct firedtv *fdtv, u64 addr, __be32 data[])
|
||||
{
|
||||
return hpsb_node_lock(node_of(fdtv), addr, EXTCODE_COMPARE_SWAP, data,
|
||||
(__force quadlet_t)arg);
|
||||
int ret;
|
||||
|
||||
ret = hpsb_node_lock(node_of(fdtv), addr, EXTCODE_COMPARE_SWAP,
|
||||
(__force quadlet_t *)&data[1], (__force quadlet_t)data[0]);
|
||||
data[0] = data[1];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int node_read(struct firedtv *fdtv, u64 addr, void *data, size_t len)
|
||||
static int node_read(struct firedtv *fdtv, u64 addr, void *data)
|
||||
{
|
||||
return hpsb_node_read(node_of(fdtv), addr, data, len);
|
||||
return hpsb_node_read(node_of(fdtv), addr, data, 4);
|
||||
}
|
||||
|
||||
static int node_write(struct firedtv *fdtv, u64 addr, void *data, size_t len)
|
||||
|
|
@ -212,6 +220,7 @@ static int node_probe(struct device *dev)
|
|||
goto fail;
|
||||
|
||||
avc_register_remote_control(fdtv);
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
spin_lock_irq(&node_list_lock);
|
||||
|
|
@ -220,6 +229,7 @@ fail:
|
|||
fdtv_unregister_rc(fdtv);
|
||||
fail_free:
|
||||
kfree(fdtv);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
@ -233,10 +243,9 @@ static int node_remove(struct device *dev)
|
|||
list_del(&fdtv->list);
|
||||
spin_unlock_irq(&node_list_lock);
|
||||
|
||||
cancel_work_sync(&fdtv->remote_ctrl_work);
|
||||
fdtv_unregister_rc(fdtv);
|
||||
|
||||
kfree(fdtv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -252,6 +261,7 @@ static int node_update(struct unit_directory *ud)
|
|||
|
||||
static struct hpsb_protocol_driver fdtv_driver = {
|
||||
.name = "firedtv",
|
||||
.id_table = fdtv_id_table,
|
||||
.update = node_update,
|
||||
.driver = {
|
||||
.probe = node_probe,
|
||||
|
|
@ -264,12 +274,11 @@ static struct hpsb_highlevel fdtv_highlevel = {
|
|||
.fcp_request = fcp_request,
|
||||
};
|
||||
|
||||
int __init fdtv_1394_init(struct ieee1394_device_id id_table[])
|
||||
int __init fdtv_1394_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
hpsb_register_highlevel(&fdtv_highlevel);
|
||||
fdtv_driver.id_table = id_table;
|
||||
ret = hpsb_register_protocol(&fdtv_driver);
|
||||
if (ret) {
|
||||
printk(KERN_ERR "firedtv: failed to register protocol\n");
|
||||
|
|
|
|||
|
|
@ -1236,14 +1236,14 @@ int avc_ca_get_mmi(struct firedtv *fdtv, char *mmi_object, unsigned int *len)
|
|||
|
||||
#define CMP_OUTPUT_PLUG_CONTROL_REG_0 0xfffff0000904ULL
|
||||
|
||||
static int cmp_read(struct firedtv *fdtv, void *buf, u64 addr, size_t len)
|
||||
static int cmp_read(struct firedtv *fdtv, u64 addr, __be32 *data)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (mutex_lock_interruptible(&fdtv->avc_mutex))
|
||||
return -EINTR;
|
||||
|
||||
ret = fdtv->backend->read(fdtv, addr, buf, len);
|
||||
ret = fdtv->backend->read(fdtv, addr, data);
|
||||
if (ret < 0)
|
||||
dev_err(fdtv->device, "CMP: read I/O error\n");
|
||||
|
||||
|
|
@ -1251,14 +1251,14 @@ static int cmp_read(struct firedtv *fdtv, void *buf, u64 addr, size_t len)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int cmp_lock(struct firedtv *fdtv, void *data, u64 addr, __be32 arg)
|
||||
static int cmp_lock(struct firedtv *fdtv, u64 addr, __be32 data[])
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (mutex_lock_interruptible(&fdtv->avc_mutex))
|
||||
return -EINTR;
|
||||
|
||||
ret = fdtv->backend->lock(fdtv, addr, data, arg);
|
||||
ret = fdtv->backend->lock(fdtv, addr, data);
|
||||
if (ret < 0)
|
||||
dev_err(fdtv->device, "CMP: lock I/O error\n");
|
||||
|
||||
|
|
@ -1288,25 +1288,25 @@ static inline void set_opcr(__be32 *opcr, u32 value, u32 mask, u32 shift)
|
|||
|
||||
int cmp_establish_pp_connection(struct firedtv *fdtv, int plug, int channel)
|
||||
{
|
||||
__be32 old_opcr, opcr;
|
||||
__be32 old_opcr, opcr[2];
|
||||
u64 opcr_address = CMP_OUTPUT_PLUG_CONTROL_REG_0 + (plug << 2);
|
||||
int attempts = 0;
|
||||
int ret;
|
||||
|
||||
ret = cmp_read(fdtv, &opcr, opcr_address, 4);
|
||||
ret = cmp_read(fdtv, opcr_address, opcr);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
repeat:
|
||||
if (!get_opcr_online(opcr)) {
|
||||
if (!get_opcr_online(*opcr)) {
|
||||
dev_err(fdtv->device, "CMP: output offline\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
old_opcr = opcr;
|
||||
old_opcr = *opcr;
|
||||
|
||||
if (get_opcr_p2p_connections(opcr)) {
|
||||
if (get_opcr_channel(opcr) != channel) {
|
||||
if (get_opcr_p2p_connections(*opcr)) {
|
||||
if (get_opcr_channel(*opcr) != channel) {
|
||||
dev_err(fdtv->device, "CMP: cannot change channel\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
|
@ -1314,11 +1314,11 @@ repeat:
|
|||
|
||||
/* We don't allocate isochronous resources. */
|
||||
} else {
|
||||
set_opcr_channel(&opcr, channel);
|
||||
set_opcr_data_rate(&opcr, 2); /* S400 */
|
||||
set_opcr_channel(opcr, channel);
|
||||
set_opcr_data_rate(opcr, 2); /* S400 */
|
||||
|
||||
/* FIXME: this is for the worst case - optimize */
|
||||
set_opcr_overhead_id(&opcr, 0);
|
||||
set_opcr_overhead_id(opcr, 0);
|
||||
|
||||
/*
|
||||
* FIXME: allocate isochronous channel and bandwidth at IRM
|
||||
|
|
@ -1326,13 +1326,16 @@ repeat:
|
|||
*/
|
||||
}
|
||||
|
||||
set_opcr_p2p_connections(&opcr, get_opcr_p2p_connections(opcr) + 1);
|
||||
set_opcr_p2p_connections(opcr, get_opcr_p2p_connections(*opcr) + 1);
|
||||
|
||||
ret = cmp_lock(fdtv, &opcr, opcr_address, old_opcr);
|
||||
opcr[1] = *opcr;
|
||||
opcr[0] = old_opcr;
|
||||
|
||||
ret = cmp_lock(fdtv, opcr_address, opcr);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (old_opcr != opcr) {
|
||||
if (old_opcr != *opcr) {
|
||||
/*
|
||||
* FIXME: if old_opcr.P2P_Connections > 0,
|
||||
* deallocate isochronous channel and bandwidth at IRM
|
||||
|
|
@ -1350,27 +1353,30 @@ repeat:
|
|||
|
||||
void cmp_break_pp_connection(struct firedtv *fdtv, int plug, int channel)
|
||||
{
|
||||
__be32 old_opcr, opcr;
|
||||
__be32 old_opcr, opcr[2];
|
||||
u64 opcr_address = CMP_OUTPUT_PLUG_CONTROL_REG_0 + (plug << 2);
|
||||
int attempts = 0;
|
||||
|
||||
if (cmp_read(fdtv, &opcr, opcr_address, 4) < 0)
|
||||
if (cmp_read(fdtv, opcr_address, opcr) < 0)
|
||||
return;
|
||||
|
||||
repeat:
|
||||
if (!get_opcr_online(opcr) || !get_opcr_p2p_connections(opcr) ||
|
||||
get_opcr_channel(opcr) != channel) {
|
||||
if (!get_opcr_online(*opcr) || !get_opcr_p2p_connections(*opcr) ||
|
||||
get_opcr_channel(*opcr) != channel) {
|
||||
dev_err(fdtv->device, "CMP: no connection to break\n");
|
||||
return;
|
||||
}
|
||||
|
||||
old_opcr = opcr;
|
||||
set_opcr_p2p_connections(&opcr, get_opcr_p2p_connections(opcr) - 1);
|
||||
old_opcr = *opcr;
|
||||
set_opcr_p2p_connections(opcr, get_opcr_p2p_connections(*opcr) - 1);
|
||||
|
||||
if (cmp_lock(fdtv, &opcr, opcr_address, old_opcr) < 0)
|
||||
opcr[1] = *opcr;
|
||||
opcr[0] = old_opcr;
|
||||
|
||||
if (cmp_lock(fdtv, opcr_address, opcr) < 0)
|
||||
return;
|
||||
|
||||
if (old_opcr != opcr) {
|
||||
if (old_opcr != *opcr) {
|
||||
/*
|
||||
* FIXME: if old_opcr.P2P_Connections == 1, i.e. we were last
|
||||
* owner, deallocate isochronous channel and bandwidth at IRM
|
||||
|
|
|
|||
|
|
@ -297,7 +297,7 @@ struct firedtv *fdtv_alloc(struct device *dev,
|
|||
#define AVC_UNIT_SPEC_ID_ENTRY 0x00a02d
|
||||
#define AVC_SW_VERSION_ENTRY 0x010001
|
||||
|
||||
static struct ieee1394_device_id fdtv_id_table[] = {
|
||||
const struct ieee1394_device_id fdtv_id_table[] = {
|
||||
{
|
||||
/* FloppyDTV S/CI and FloppyDTV S2 */
|
||||
.match_flags = MATCH_FLAGS,
|
||||
|
|
@ -346,12 +346,23 @@ MODULE_DEVICE_TABLE(ieee1394, fdtv_id_table);
|
|||
|
||||
static int __init fdtv_init(void)
|
||||
{
|
||||
return fdtv_1394_init(fdtv_id_table);
|
||||
int ret;
|
||||
|
||||
ret = fdtv_fw_init();
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = fdtv_1394_init();
|
||||
if (ret < 0)
|
||||
fdtv_fw_exit();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit fdtv_exit(void)
|
||||
{
|
||||
fdtv_1394_exit();
|
||||
fdtv_fw_exit();
|
||||
}
|
||||
|
||||
module_init(fdtv_init);
|
||||
|
|
|
|||
376
drivers/media/dvb/firewire/firedtv-fw.c
Normal file
376
drivers/media/dvb/firewire/firedtv-fw.c
Normal file
|
|
@ -0,0 +1,376 @@
|
|||
/*
|
||||
* FireDTV driver -- firewire I/O backend
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/firewire.h>
|
||||
#include <linux/firewire-constants.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <asm/page.h>
|
||||
|
||||
#include <dvb_demux.h>
|
||||
|
||||
#include "firedtv.h"
|
||||
|
||||
static LIST_HEAD(node_list);
|
||||
static DEFINE_SPINLOCK(node_list_lock);
|
||||
|
||||
static inline struct fw_device *device_of(struct firedtv *fdtv)
|
||||
{
|
||||
return fw_device(fdtv->device->parent);
|
||||
}
|
||||
|
||||
static int node_req(struct firedtv *fdtv, u64 addr, void *data, size_t len,
|
||||
int tcode)
|
||||
{
|
||||
struct fw_device *device = device_of(fdtv);
|
||||
int rcode, generation = device->generation;
|
||||
|
||||
smp_rmb(); /* node_id vs. generation */
|
||||
|
||||
rcode = fw_run_transaction(device->card, tcode, device->node_id,
|
||||
generation, device->max_speed, addr, data, len);
|
||||
|
||||
return rcode != RCODE_COMPLETE ? -EIO : 0;
|
||||
}
|
||||
|
||||
static int node_lock(struct firedtv *fdtv, u64 addr, __be32 data[])
|
||||
{
|
||||
return node_req(fdtv, addr, data, 8, TCODE_LOCK_COMPARE_SWAP);
|
||||
}
|
||||
|
||||
static int node_read(struct firedtv *fdtv, u64 addr, void *data)
|
||||
{
|
||||
return node_req(fdtv, addr, data, 4, TCODE_READ_QUADLET_REQUEST);
|
||||
}
|
||||
|
||||
static int node_write(struct firedtv *fdtv, u64 addr, void *data, size_t len)
|
||||
{
|
||||
return node_req(fdtv, addr, data, len, TCODE_WRITE_BLOCK_REQUEST);
|
||||
}
|
||||
|
||||
#define ISO_HEADER_SIZE 4
|
||||
#define CIP_HEADER_SIZE 8
|
||||
#define MPEG2_TS_HEADER_SIZE 4
|
||||
#define MPEG2_TS_SOURCE_PACKET_SIZE (4 + 188)
|
||||
|
||||
#define MAX_PACKET_SIZE 1024 /* 776, rounded up to 2^n */
|
||||
#define PACKETS_PER_PAGE (PAGE_SIZE / MAX_PACKET_SIZE)
|
||||
#define N_PACKETS 64 /* buffer size */
|
||||
#define N_PAGES DIV_ROUND_UP(N_PACKETS, PACKETS_PER_PAGE)
|
||||
#define IRQ_INTERVAL 16
|
||||
|
||||
struct firedtv_receive_context {
|
||||
struct fw_iso_context *context;
|
||||
struct fw_iso_buffer buffer;
|
||||
int interrupt_packet;
|
||||
int current_packet;
|
||||
char *pages[N_PAGES];
|
||||
};
|
||||
|
||||
static int queue_iso(struct firedtv_receive_context *ctx, int index)
|
||||
{
|
||||
struct fw_iso_packet p;
|
||||
|
||||
p.payload_length = MAX_PACKET_SIZE;
|
||||
p.interrupt = !(++ctx->interrupt_packet & (IRQ_INTERVAL - 1));
|
||||
p.skip = 0;
|
||||
p.header_length = ISO_HEADER_SIZE;
|
||||
|
||||
return fw_iso_context_queue(ctx->context, &p, &ctx->buffer,
|
||||
index * MAX_PACKET_SIZE);
|
||||
}
|
||||
|
||||
static void handle_iso(struct fw_iso_context *context, u32 cycle,
|
||||
size_t header_length, void *header, void *data)
|
||||
{
|
||||
struct firedtv *fdtv = data;
|
||||
struct firedtv_receive_context *ctx = fdtv->backend_data;
|
||||
__be32 *h, *h_end;
|
||||
int length, err, i = ctx->current_packet;
|
||||
char *p, *p_end;
|
||||
|
||||
for (h = header, h_end = h + header_length / 4; h < h_end; h++) {
|
||||
length = be32_to_cpup(h) >> 16;
|
||||
if (unlikely(length > MAX_PACKET_SIZE)) {
|
||||
dev_err(fdtv->device, "length = %d\n", length);
|
||||
length = MAX_PACKET_SIZE;
|
||||
}
|
||||
|
||||
p = ctx->pages[i / PACKETS_PER_PAGE]
|
||||
+ (i % PACKETS_PER_PAGE) * MAX_PACKET_SIZE;
|
||||
p_end = p + length;
|
||||
|
||||
for (p += CIP_HEADER_SIZE + MPEG2_TS_HEADER_SIZE; p < p_end;
|
||||
p += MPEG2_TS_SOURCE_PACKET_SIZE)
|
||||
dvb_dmx_swfilter_packets(&fdtv->demux, p, 1);
|
||||
|
||||
err = queue_iso(ctx, i);
|
||||
if (unlikely(err))
|
||||
dev_err(fdtv->device, "requeue failed\n");
|
||||
|
||||
i = (i + 1) & (N_PACKETS - 1);
|
||||
}
|
||||
ctx->current_packet = i;
|
||||
}
|
||||
|
||||
static int start_iso(struct firedtv *fdtv)
|
||||
{
|
||||
struct firedtv_receive_context *ctx;
|
||||
struct fw_device *device = device_of(fdtv);
|
||||
int i, err;
|
||||
|
||||
ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
|
||||
if (!ctx)
|
||||
return -ENOMEM;
|
||||
|
||||
ctx->context = fw_iso_context_create(device->card,
|
||||
FW_ISO_CONTEXT_RECEIVE, fdtv->isochannel,
|
||||
device->max_speed, ISO_HEADER_SIZE, handle_iso, fdtv);
|
||||
if (IS_ERR(ctx->context)) {
|
||||
err = PTR_ERR(ctx->context);
|
||||
goto fail_free;
|
||||
}
|
||||
|
||||
err = fw_iso_buffer_init(&ctx->buffer, device->card,
|
||||
N_PAGES, DMA_FROM_DEVICE);
|
||||
if (err)
|
||||
goto fail_context_destroy;
|
||||
|
||||
ctx->interrupt_packet = 0;
|
||||
ctx->current_packet = 0;
|
||||
|
||||
for (i = 0; i < N_PAGES; i++)
|
||||
ctx->pages[i] = page_address(ctx->buffer.pages[i]);
|
||||
|
||||
for (i = 0; i < N_PACKETS; i++) {
|
||||
err = queue_iso(ctx, i);
|
||||
if (err)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
err = fw_iso_context_start(ctx->context, -1, 0,
|
||||
FW_ISO_CONTEXT_MATCH_ALL_TAGS);
|
||||
if (err)
|
||||
goto fail;
|
||||
|
||||
fdtv->backend_data = ctx;
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
fw_iso_buffer_destroy(&ctx->buffer, device->card);
|
||||
fail_context_destroy:
|
||||
fw_iso_context_destroy(ctx->context);
|
||||
fail_free:
|
||||
kfree(ctx);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void stop_iso(struct firedtv *fdtv)
|
||||
{
|
||||
struct firedtv_receive_context *ctx = fdtv->backend_data;
|
||||
|
||||
fw_iso_context_stop(ctx->context);
|
||||
fw_iso_buffer_destroy(&ctx->buffer, device_of(fdtv)->card);
|
||||
fw_iso_context_destroy(ctx->context);
|
||||
kfree(ctx);
|
||||
}
|
||||
|
||||
static const struct firedtv_backend backend = {
|
||||
.lock = node_lock,
|
||||
.read = node_read,
|
||||
.write = node_write,
|
||||
.start_iso = start_iso,
|
||||
.stop_iso = stop_iso,
|
||||
};
|
||||
|
||||
static void handle_fcp(struct fw_card *card, struct fw_request *request,
|
||||
int tcode, int destination, int source, int generation,
|
||||
int speed, unsigned long long offset,
|
||||
void *payload, size_t length, void *callback_data)
|
||||
{
|
||||
struct firedtv *f, *fdtv = NULL;
|
||||
struct fw_device *device;
|
||||
unsigned long flags;
|
||||
int su;
|
||||
|
||||
if ((tcode != TCODE_WRITE_QUADLET_REQUEST &&
|
||||
tcode != TCODE_WRITE_BLOCK_REQUEST) ||
|
||||
offset != CSR_REGISTER_BASE + CSR_FCP_RESPONSE ||
|
||||
length == 0 ||
|
||||
(((u8 *)payload)[0] & 0xf0) != 0) {
|
||||
fw_send_response(card, request, RCODE_TYPE_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
su = ((u8 *)payload)[1] & 0x7;
|
||||
|
||||
spin_lock_irqsave(&node_list_lock, flags);
|
||||
list_for_each_entry(f, &node_list, list) {
|
||||
device = device_of(f);
|
||||
if (device->generation != generation)
|
||||
continue;
|
||||
|
||||
smp_rmb(); /* node_id vs. generation */
|
||||
|
||||
if (device->card == card &&
|
||||
device->node_id == source &&
|
||||
(f->subunit == su || (f->subunit == 0 && su == 0x7))) {
|
||||
fdtv = f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&node_list_lock, flags);
|
||||
|
||||
if (fdtv) {
|
||||
avc_recv(fdtv, payload, length);
|
||||
fw_send_response(card, request, RCODE_COMPLETE);
|
||||
}
|
||||
}
|
||||
|
||||
static struct fw_address_handler fcp_handler = {
|
||||
.length = CSR_FCP_END - CSR_FCP_RESPONSE,
|
||||
.address_callback = handle_fcp,
|
||||
};
|
||||
|
||||
static const struct fw_address_region fcp_region = {
|
||||
.start = CSR_REGISTER_BASE + CSR_FCP_RESPONSE,
|
||||
.end = CSR_REGISTER_BASE + CSR_FCP_END,
|
||||
};
|
||||
|
||||
/* Adjust the template string if models with longer names appear. */
|
||||
#define MAX_MODEL_NAME_LEN ((int)DIV_ROUND_UP(sizeof("FireDTV ????"), 4))
|
||||
|
||||
static size_t model_name(u32 *directory, __be32 *buffer)
|
||||
{
|
||||
struct fw_csr_iterator ci;
|
||||
int i, length, key, value, last_key = 0;
|
||||
u32 *block = NULL;
|
||||
|
||||
fw_csr_iterator_init(&ci, directory);
|
||||
while (fw_csr_iterator_next(&ci, &key, &value)) {
|
||||
if (last_key == CSR_MODEL &&
|
||||
key == (CSR_DESCRIPTOR | CSR_LEAF))
|
||||
block = ci.p - 1 + value;
|
||||
last_key = key;
|
||||
}
|
||||
|
||||
if (block == NULL)
|
||||
return 0;
|
||||
|
||||
length = min((int)(block[0] >> 16) - 2, MAX_MODEL_NAME_LEN);
|
||||
if (length <= 0)
|
||||
return 0;
|
||||
|
||||
/* fast-forward to text string */
|
||||
block += 3;
|
||||
|
||||
for (i = 0; i < length; i++)
|
||||
buffer[i] = cpu_to_be32(block[i]);
|
||||
|
||||
return length * 4;
|
||||
}
|
||||
|
||||
static int node_probe(struct device *dev)
|
||||
{
|
||||
struct firedtv *fdtv;
|
||||
__be32 name[MAX_MODEL_NAME_LEN];
|
||||
int name_len, err;
|
||||
|
||||
name_len = model_name(fw_unit(dev)->directory, name);
|
||||
|
||||
fdtv = fdtv_alloc(dev, &backend, (char *)name, name_len);
|
||||
if (!fdtv)
|
||||
return -ENOMEM;
|
||||
|
||||
err = fdtv_register_rc(fdtv, dev);
|
||||
if (err)
|
||||
goto fail_free;
|
||||
|
||||
spin_lock_irq(&node_list_lock);
|
||||
list_add_tail(&fdtv->list, &node_list);
|
||||
spin_unlock_irq(&node_list_lock);
|
||||
|
||||
err = avc_identify_subunit(fdtv);
|
||||
if (err)
|
||||
goto fail;
|
||||
|
||||
err = fdtv_dvb_register(fdtv);
|
||||
if (err)
|
||||
goto fail;
|
||||
|
||||
avc_register_remote_control(fdtv);
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
spin_lock_irq(&node_list_lock);
|
||||
list_del(&fdtv->list);
|
||||
spin_unlock_irq(&node_list_lock);
|
||||
fdtv_unregister_rc(fdtv);
|
||||
fail_free:
|
||||
kfree(fdtv);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int node_remove(struct device *dev)
|
||||
{
|
||||
struct firedtv *fdtv = dev_get_drvdata(dev);
|
||||
|
||||
fdtv_dvb_unregister(fdtv);
|
||||
|
||||
spin_lock_irq(&node_list_lock);
|
||||
list_del(&fdtv->list);
|
||||
spin_unlock_irq(&node_list_lock);
|
||||
|
||||
fdtv_unregister_rc(fdtv);
|
||||
|
||||
kfree(fdtv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void node_update(struct fw_unit *unit)
|
||||
{
|
||||
struct firedtv *fdtv = dev_get_drvdata(&unit->device);
|
||||
|
||||
if (fdtv->isochannel >= 0)
|
||||
cmp_establish_pp_connection(fdtv, fdtv->subunit,
|
||||
fdtv->isochannel);
|
||||
}
|
||||
|
||||
static struct fw_driver fdtv_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "firedtv",
|
||||
.bus = &fw_bus_type,
|
||||
.probe = node_probe,
|
||||
.remove = node_remove,
|
||||
},
|
||||
.update = node_update,
|
||||
.id_table = fdtv_id_table,
|
||||
};
|
||||
|
||||
int __init fdtv_fw_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = fw_core_add_address_handler(&fcp_handler, &fcp_region);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return driver_register(&fdtv_driver.driver);
|
||||
}
|
||||
|
||||
void fdtv_fw_exit(void)
|
||||
{
|
||||
driver_unregister(&fdtv_driver.driver);
|
||||
fw_core_remove_address_handler(&fcp_handler);
|
||||
}
|
||||
|
|
@ -14,6 +14,7 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include "firedtv.h"
|
||||
|
||||
|
|
@ -163,6 +164,7 @@ fail:
|
|||
|
||||
void fdtv_unregister_rc(struct firedtv *fdtv)
|
||||
{
|
||||
cancel_work_sync(&fdtv->remote_ctrl_work);
|
||||
kfree(fdtv->remote_ctrl_dev->keycode);
|
||||
input_unregister_device(fdtv->remote_ctrl_dev);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
#include <linux/dvb/dmx.h>
|
||||
#include <linux/dvb/frontend.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/spinlock_types.h>
|
||||
#include <linux/types.h>
|
||||
|
|
@ -72,8 +73,8 @@ struct input_dev;
|
|||
struct firedtv;
|
||||
|
||||
struct firedtv_backend {
|
||||
int (*lock)(struct firedtv *fdtv, u64 addr, void *data, __be32 arg);
|
||||
int (*read)(struct firedtv *fdtv, u64 addr, void *data, size_t len);
|
||||
int (*lock)(struct firedtv *fdtv, u64 addr, __be32 data[]);
|
||||
int (*read)(struct firedtv *fdtv, u64 addr, void *data);
|
||||
int (*write)(struct firedtv *fdtv, u64 addr, void *data, size_t len);
|
||||
int (*start_iso)(struct firedtv *fdtv);
|
||||
void (*stop_iso)(struct firedtv *fdtv);
|
||||
|
|
@ -119,10 +120,10 @@ struct firedtv {
|
|||
|
||||
/* firedtv-1394.c */
|
||||
#ifdef CONFIG_DVB_FIREDTV_IEEE1394
|
||||
int fdtv_1394_init(struct ieee1394_device_id id_table[]);
|
||||
int fdtv_1394_init(void);
|
||||
void fdtv_1394_exit(void);
|
||||
#else
|
||||
static inline int fdtv_1394_init(struct ieee1394_device_id it[]) { return 0; }
|
||||
static inline int fdtv_1394_init(void) { return 0; }
|
||||
static inline void fdtv_1394_exit(void) {}
|
||||
#endif
|
||||
|
||||
|
|
@ -163,10 +164,20 @@ struct firedtv *fdtv_alloc(struct device *dev,
|
|||
const struct firedtv_backend *backend,
|
||||
const char *name, size_t name_len);
|
||||
extern const char *fdtv_model_names[];
|
||||
extern const struct ieee1394_device_id fdtv_id_table[];
|
||||
|
||||
/* firedtv-fe.c */
|
||||
void fdtv_frontend_init(struct firedtv *fdtv);
|
||||
|
||||
/* firedtv-fw.c */
|
||||
#ifdef CONFIG_DVB_FIREDTV_FIREWIRE
|
||||
int fdtv_fw_init(void);
|
||||
void fdtv_fw_exit(void);
|
||||
#else
|
||||
static inline int fdtv_fw_init(void) { return 0; }
|
||||
static inline void fdtv_fw_exit(void) {}
|
||||
#endif
|
||||
|
||||
/* firedtv-rc.c */
|
||||
#ifdef CONFIG_DVB_FIREDTV_INPUT
|
||||
int fdtv_register_rc(struct firedtv *fdtv, struct device *dev);
|
||||
|
|
|
|||
|
|
@ -201,6 +201,13 @@ config DVB_SI21XX
|
|||
help
|
||||
A DVB-S tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_DS3000
|
||||
tristate "Montage Tehnology DS3000 based"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if DVB_FE_CUSTOMISE
|
||||
help
|
||||
A DVB-S/S2 tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
comment "DVB-T (terrestrial) frontends"
|
||||
depends on DVB_CORE
|
||||
|
||||
|
|
@ -342,6 +349,13 @@ config DVB_AF9013
|
|||
help
|
||||
Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_EC100
|
||||
tristate "E3C EC100"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if DVB_FE_CUSTOMISE
|
||||
help
|
||||
Say Y when you want to support this frontend.
|
||||
|
||||
comment "DVB-C (cable) frontends"
|
||||
depends on DVB_CORE
|
||||
|
||||
|
|
@ -557,6 +571,13 @@ config DVB_LGS8GXX
|
|||
help
|
||||
A DMB-TH tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
config DVB_ATBM8830
|
||||
tristate "AltoBeam ATBM8830/8831 DMB-TH demodulator"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if DVB_FE_CUSTOMISE
|
||||
help
|
||||
A DMB-TH tuner module. Say Y when you want to support this frontend.
|
||||
|
||||
comment "Tools to develop new frontends"
|
||||
|
||||
config DVB_DUMMY_FE
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ obj-$(CONFIG_DVB_TUNER_CX24113) += cx24113.o
|
|||
obj-$(CONFIG_DVB_S5H1411) += s5h1411.o
|
||||
obj-$(CONFIG_DVB_LGS8GL5) += lgs8gl5.o
|
||||
obj-$(CONFIG_DVB_LGS8GXX) += lgs8gxx.o
|
||||
obj-$(CONFIG_DVB_ATBM8830) += atbm8830.o
|
||||
obj-$(CONFIG_DVB_DUMMY_FE) += dvb_dummy_fe.o
|
||||
obj-$(CONFIG_DVB_AF9013) += af9013.o
|
||||
obj-$(CONFIG_DVB_CX24116) += cx24116.o
|
||||
|
|
@ -76,3 +77,5 @@ obj-$(CONFIG_DVB_STV0900) += stv0900.o
|
|||
obj-$(CONFIG_DVB_STV090x) += stv090x.o
|
||||
obj-$(CONFIG_DVB_STV6110x) += stv6110x.o
|
||||
obj-$(CONFIG_DVB_ISL6423) += isl6423.o
|
||||
obj-$(CONFIG_DVB_EC100) += ec100.o
|
||||
obj-$(CONFIG_DVB_DS3000) += ds3000.o
|
||||
|
|
|
|||
495
drivers/media/dvb/frontends/atbm8830.c
Normal file
495
drivers/media/dvb/frontends/atbm8830.c
Normal file
|
|
@ -0,0 +1,495 @@
|
|||
/*
|
||||
* Support for AltoBeam GB20600 (a.k.a DMB-TH) demodulator
|
||||
* ATBM8830, ATBM8831
|
||||
*
|
||||
* Copyright (C) 2009 David T.L. Wong <davidtlwong@gmail.com>
|
||||
*
|
||||
* 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 <asm/div64.h>
|
||||
#include "dvb_frontend.h"
|
||||
|
||||
#include "atbm8830.h"
|
||||
#include "atbm8830_priv.h"
|
||||
|
||||
#define dprintk(args...) \
|
||||
do { \
|
||||
if (debug) \
|
||||
printk(KERN_DEBUG "atbm8830: " args); \
|
||||
} while (0)
|
||||
|
||||
static int debug;
|
||||
|
||||
module_param(debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
|
||||
|
||||
static int atbm8830_write_reg(struct atbm_state *priv, u16 reg, u8 data)
|
||||
{
|
||||
int ret = 0;
|
||||
u8 dev_addr;
|
||||
u8 buf1[] = { reg >> 8, reg & 0xFF };
|
||||
u8 buf2[] = { data };
|
||||
struct i2c_msg msg1 = { .flags = 0, .buf = buf1, .len = 2 };
|
||||
struct i2c_msg msg2 = { .flags = 0, .buf = buf2, .len = 1 };
|
||||
|
||||
dev_addr = priv->config->demod_address;
|
||||
msg1.addr = dev_addr;
|
||||
msg2.addr = dev_addr;
|
||||
|
||||
if (debug >= 2)
|
||||
printk(KERN_DEBUG "%s: reg=0x%04X, data=0x%02X\n",
|
||||
__func__, reg, data);
|
||||
|
||||
ret = i2c_transfer(priv->i2c, &msg1, 1);
|
||||
if (ret != 1)
|
||||
return -EIO;
|
||||
|
||||
ret = i2c_transfer(priv->i2c, &msg2, 1);
|
||||
return (ret != 1) ? -EIO : 0;
|
||||
}
|
||||
|
||||
static int atbm8830_read_reg(struct atbm_state *priv, u16 reg, u8 *p_data)
|
||||
{
|
||||
int ret;
|
||||
u8 dev_addr;
|
||||
|
||||
u8 buf1[] = { reg >> 8, reg & 0xFF };
|
||||
u8 buf2[] = { 0 };
|
||||
struct i2c_msg msg1 = { .flags = 0, .buf = buf1, .len = 2 };
|
||||
struct i2c_msg msg2 = { .flags = I2C_M_RD, .buf = buf2, .len = 1 };
|
||||
|
||||
dev_addr = priv->config->demod_address;
|
||||
msg1.addr = dev_addr;
|
||||
msg2.addr = dev_addr;
|
||||
|
||||
ret = i2c_transfer(priv->i2c, &msg1, 1);
|
||||
if (ret != 1) {
|
||||
dprintk(KERN_DEBUG "%s: error reg=0x%04x, ret=%i\n",
|
||||
__func__, reg, ret);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
ret = i2c_transfer(priv->i2c, &msg2, 1);
|
||||
if (ret != 1)
|
||||
return -EIO;
|
||||
|
||||
*p_data = buf2[0];
|
||||
if (debug >= 2)
|
||||
printk(KERN_DEBUG "%s: reg=0x%04X, data=0x%02X\n",
|
||||
__func__, reg, buf2[0]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Lock register latch so that multi-register read is atomic */
|
||||
static inline int atbm8830_reglatch_lock(struct atbm_state *priv, int lock)
|
||||
{
|
||||
return atbm8830_write_reg(priv, REG_READ_LATCH, lock ? 1 : 0);
|
||||
}
|
||||
|
||||
static int set_osc_freq(struct atbm_state *priv, u32 freq /*in kHz*/)
|
||||
{
|
||||
u32 val;
|
||||
u64 t;
|
||||
|
||||
/* 0x100000 * freq / 30.4MHz */
|
||||
t = (u64)0x100000 * freq;
|
||||
do_div(t, 30400);
|
||||
val = t;
|
||||
|
||||
atbm8830_write_reg(priv, REG_OSC_CLK, val);
|
||||
atbm8830_write_reg(priv, REG_OSC_CLK + 1, val >> 8);
|
||||
atbm8830_write_reg(priv, REG_OSC_CLK + 2, val >> 16);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_if_freq(struct atbm_state *priv, u32 freq /*in kHz*/)
|
||||
{
|
||||
|
||||
u32 fs = priv->config->osc_clk_freq;
|
||||
u64 t;
|
||||
u32 val;
|
||||
u8 dat;
|
||||
|
||||
if (freq != 0) {
|
||||
/* 2 * PI * (freq - fs) / fs * (2 ^ 22) */
|
||||
t = (u64) 2 * 31416 * (freq - fs);
|
||||
t <<= 22;
|
||||
do_div(t, fs);
|
||||
do_div(t, 1000);
|
||||
val = t;
|
||||
|
||||
atbm8830_write_reg(priv, REG_TUNER_BASEBAND, 1);
|
||||
atbm8830_write_reg(priv, REG_IF_FREQ, val);
|
||||
atbm8830_write_reg(priv, REG_IF_FREQ+1, val >> 8);
|
||||
atbm8830_write_reg(priv, REG_IF_FREQ+2, val >> 16);
|
||||
|
||||
atbm8830_read_reg(priv, REG_ADC_CONFIG, &dat);
|
||||
dat &= 0xFC;
|
||||
atbm8830_write_reg(priv, REG_ADC_CONFIG, dat);
|
||||
} else {
|
||||
/* Zero IF */
|
||||
atbm8830_write_reg(priv, REG_TUNER_BASEBAND, 0);
|
||||
|
||||
atbm8830_read_reg(priv, REG_ADC_CONFIG, &dat);
|
||||
dat &= 0xFC;
|
||||
dat |= 0x02;
|
||||
atbm8830_write_reg(priv, REG_ADC_CONFIG, dat);
|
||||
|
||||
if (priv->config->zif_swap_iq)
|
||||
atbm8830_write_reg(priv, REG_SWAP_I_Q, 0x03);
|
||||
else
|
||||
atbm8830_write_reg(priv, REG_SWAP_I_Q, 0x01);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int is_locked(struct atbm_state *priv, u8 *locked)
|
||||
{
|
||||
u8 status;
|
||||
|
||||
atbm8830_read_reg(priv, REG_LOCK_STATUS, &status);
|
||||
|
||||
if (locked != NULL)
|
||||
*locked = (status == 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int set_static_channel_mode(struct atbm_state *priv)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 5; i++)
|
||||
atbm8830_write_reg(priv, 0x099B + i, 0x08);
|
||||
|
||||
atbm8830_write_reg(priv, 0x095B, 0x7F);
|
||||
atbm8830_write_reg(priv, 0x09CB, 0x01);
|
||||
atbm8830_write_reg(priv, 0x09CC, 0x7F);
|
||||
atbm8830_write_reg(priv, 0x09CD, 0x7F);
|
||||
atbm8830_write_reg(priv, 0x0E01, 0x20);
|
||||
|
||||
/* For single carrier */
|
||||
atbm8830_write_reg(priv, 0x0B03, 0x0A);
|
||||
atbm8830_write_reg(priv, 0x0935, 0x10);
|
||||
atbm8830_write_reg(priv, 0x0936, 0x08);
|
||||
atbm8830_write_reg(priv, 0x093E, 0x08);
|
||||
atbm8830_write_reg(priv, 0x096E, 0x06);
|
||||
|
||||
/* frame_count_max0 */
|
||||
atbm8830_write_reg(priv, 0x0B09, 0x00);
|
||||
/* frame_count_max1 */
|
||||
atbm8830_write_reg(priv, 0x0B0A, 0x08);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_ts_config(struct atbm_state *priv)
|
||||
{
|
||||
const struct atbm8830_config *cfg = priv->config;
|
||||
|
||||
/*Set parallel/serial ts mode*/
|
||||
atbm8830_write_reg(priv, REG_TS_SERIAL, cfg->serial_ts ? 1 : 0);
|
||||
atbm8830_write_reg(priv, REG_TS_CLK_MODE, cfg->serial_ts ? 1 : 0);
|
||||
/*Set ts sampling edge*/
|
||||
atbm8830_write_reg(priv, REG_TS_SAMPLE_EDGE,
|
||||
cfg->ts_sampling_edge ? 1 : 0);
|
||||
/*Set ts clock freerun*/
|
||||
atbm8830_write_reg(priv, REG_TS_CLK_FREERUN,
|
||||
cfg->ts_clk_gated ? 0 : 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atbm8830_init(struct dvb_frontend *fe)
|
||||
{
|
||||
struct atbm_state *priv = fe->demodulator_priv;
|
||||
const struct atbm8830_config *cfg = priv->config;
|
||||
|
||||
/*Set oscillator frequency*/
|
||||
set_osc_freq(priv, cfg->osc_clk_freq);
|
||||
|
||||
/*Set IF frequency*/
|
||||
set_if_freq(priv, cfg->if_freq);
|
||||
|
||||
|
||||
/*Set static channel mode*/
|
||||
set_static_channel_mode(priv);
|
||||
|
||||
set_ts_config(priv);
|
||||
/*Turn off DSP reset*/
|
||||
atbm8830_write_reg(priv, 0x000A, 0);
|
||||
|
||||
/*SW version test*/
|
||||
atbm8830_write_reg(priv, 0x020C, 11);
|
||||
|
||||
/* Run */
|
||||
atbm8830_write_reg(priv, REG_DEMOD_RUN, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void atbm8830_release(struct dvb_frontend *fe)
|
||||
{
|
||||
struct atbm_state *state = fe->demodulator_priv;
|
||||
dprintk("%s\n", __func__);
|
||||
|
||||
kfree(state);
|
||||
}
|
||||
|
||||
static int atbm8830_set_fe(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_parameters *fe_params)
|
||||
{
|
||||
struct atbm_state *priv = fe->demodulator_priv;
|
||||
int i;
|
||||
u8 locked = 0;
|
||||
dprintk("%s\n", __func__);
|
||||
|
||||
/* set frequency */
|
||||
if (fe->ops.tuner_ops.set_params) {
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
fe->ops.tuner_ops.set_params(fe, fe_params);
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 0);
|
||||
}
|
||||
|
||||
/* start auto lock */
|
||||
for (i = 0; i < 10; i++) {
|
||||
mdelay(100);
|
||||
dprintk("Try %d\n", i);
|
||||
is_locked(priv, &locked);
|
||||
if (locked != 0) {
|
||||
dprintk("ATBM8830 locked!\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atbm8830_get_fe(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_parameters *fe_params)
|
||||
{
|
||||
dprintk("%s\n", __func__);
|
||||
|
||||
/* TODO: get real readings from device */
|
||||
/* inversion status */
|
||||
fe_params->inversion = INVERSION_OFF;
|
||||
|
||||
/* bandwidth */
|
||||
fe_params->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
|
||||
|
||||
fe_params->u.ofdm.code_rate_HP = FEC_AUTO;
|
||||
fe_params->u.ofdm.code_rate_LP = FEC_AUTO;
|
||||
|
||||
fe_params->u.ofdm.constellation = QAM_AUTO;
|
||||
|
||||
/* transmission mode */
|
||||
fe_params->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO;
|
||||
|
||||
/* guard interval */
|
||||
fe_params->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO;
|
||||
|
||||
/* hierarchy */
|
||||
fe_params->u.ofdm.hierarchy_information = HIERARCHY_NONE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atbm8830_get_tune_settings(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_tune_settings *fesettings)
|
||||
{
|
||||
fesettings->min_delay_ms = 0;
|
||||
fesettings->step_size = 0;
|
||||
fesettings->max_drift = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atbm8830_read_status(struct dvb_frontend *fe, fe_status_t *fe_status)
|
||||
{
|
||||
struct atbm_state *priv = fe->demodulator_priv;
|
||||
u8 locked = 0;
|
||||
u8 agc_locked = 0;
|
||||
|
||||
dprintk("%s\n", __func__);
|
||||
*fe_status = 0;
|
||||
|
||||
is_locked(priv, &locked);
|
||||
if (locked) {
|
||||
*fe_status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
|
||||
FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
|
||||
}
|
||||
dprintk("%s: fe_status=0x%x\n", __func__, *fe_status);
|
||||
|
||||
atbm8830_read_reg(priv, REG_AGC_LOCK, &agc_locked);
|
||||
dprintk("AGC Lock: %d\n", agc_locked);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atbm8830_read_ber(struct dvb_frontend *fe, u32 *ber)
|
||||
{
|
||||
struct atbm_state *priv = fe->demodulator_priv;
|
||||
u32 frame_err;
|
||||
u8 t;
|
||||
|
||||
dprintk("%s\n", __func__);
|
||||
|
||||
atbm8830_reglatch_lock(priv, 1);
|
||||
|
||||
atbm8830_read_reg(priv, REG_FRAME_ERR_CNT + 1, &t);
|
||||
frame_err = t & 0x7F;
|
||||
frame_err <<= 8;
|
||||
atbm8830_read_reg(priv, REG_FRAME_ERR_CNT, &t);
|
||||
frame_err |= t;
|
||||
|
||||
atbm8830_reglatch_lock(priv, 0);
|
||||
|
||||
*ber = frame_err * 100 / 32767;
|
||||
|
||||
dprintk("%s: ber=0x%x\n", __func__, *ber);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atbm8830_read_signal_strength(struct dvb_frontend *fe, u16 *signal)
|
||||
{
|
||||
struct atbm_state *priv = fe->demodulator_priv;
|
||||
u32 pwm;
|
||||
u8 t;
|
||||
|
||||
dprintk("%s\n", __func__);
|
||||
atbm8830_reglatch_lock(priv, 1);
|
||||
|
||||
atbm8830_read_reg(priv, REG_AGC_PWM_VAL + 1, &t);
|
||||
pwm = t & 0x03;
|
||||
pwm <<= 8;
|
||||
atbm8830_read_reg(priv, REG_AGC_PWM_VAL, &t);
|
||||
pwm |= t;
|
||||
|
||||
atbm8830_reglatch_lock(priv, 0);
|
||||
|
||||
dprintk("AGC PWM = 0x%02X\n", pwm);
|
||||
pwm = 0x400 - pwm;
|
||||
|
||||
*signal = pwm * 0x10000 / 0x400;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atbm8830_read_snr(struct dvb_frontend *fe, u16 *snr)
|
||||
{
|
||||
dprintk("%s\n", __func__);
|
||||
*snr = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atbm8830_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
|
||||
{
|
||||
dprintk("%s\n", __func__);
|
||||
*ucblocks = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atbm8830_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
|
||||
{
|
||||
struct atbm_state *priv = fe->demodulator_priv;
|
||||
|
||||
return atbm8830_write_reg(priv, REG_I2C_GATE, enable ? 1 : 0);
|
||||
}
|
||||
|
||||
static struct dvb_frontend_ops atbm8830_ops = {
|
||||
.info = {
|
||||
.name = "AltoBeam ATBM8830/8831 DMB-TH",
|
||||
.type = FE_OFDM,
|
||||
.frequency_min = 474000000,
|
||||
.frequency_max = 858000000,
|
||||
.frequency_stepsize = 10000,
|
||||
.caps =
|
||||
FE_CAN_FEC_AUTO |
|
||||
FE_CAN_QAM_AUTO |
|
||||
FE_CAN_TRANSMISSION_MODE_AUTO |
|
||||
FE_CAN_GUARD_INTERVAL_AUTO
|
||||
},
|
||||
|
||||
.release = atbm8830_release,
|
||||
|
||||
.init = atbm8830_init,
|
||||
.sleep = NULL,
|
||||
.write = NULL,
|
||||
.i2c_gate_ctrl = atbm8830_i2c_gate_ctrl,
|
||||
|
||||
.set_frontend = atbm8830_set_fe,
|
||||
.get_frontend = atbm8830_get_fe,
|
||||
.get_tune_settings = atbm8830_get_tune_settings,
|
||||
|
||||
.read_status = atbm8830_read_status,
|
||||
.read_ber = atbm8830_read_ber,
|
||||
.read_signal_strength = atbm8830_read_signal_strength,
|
||||
.read_snr = atbm8830_read_snr,
|
||||
.read_ucblocks = atbm8830_read_ucblocks,
|
||||
};
|
||||
|
||||
struct dvb_frontend *atbm8830_attach(const struct atbm8830_config *config,
|
||||
struct i2c_adapter *i2c)
|
||||
{
|
||||
struct atbm_state *priv = NULL;
|
||||
u8 data = 0;
|
||||
|
||||
dprintk("%s()\n", __func__);
|
||||
|
||||
if (config == NULL || i2c == NULL)
|
||||
return NULL;
|
||||
|
||||
priv = kzalloc(sizeof(struct atbm_state), GFP_KERNEL);
|
||||
if (priv == NULL)
|
||||
goto error_out;
|
||||
|
||||
priv->config = config;
|
||||
priv->i2c = i2c;
|
||||
|
||||
/* check if the demod is there */
|
||||
if (atbm8830_read_reg(priv, REG_CHIP_ID, &data) != 0) {
|
||||
dprintk("%s atbm8830/8831 not found at i2c addr 0x%02X\n",
|
||||
__func__, priv->config->demod_address);
|
||||
goto error_out;
|
||||
}
|
||||
dprintk("atbm8830 chip id: 0x%02X\n", data);
|
||||
|
||||
memcpy(&priv->frontend.ops, &atbm8830_ops,
|
||||
sizeof(struct dvb_frontend_ops));
|
||||
priv->frontend.demodulator_priv = priv;
|
||||
|
||||
atbm8830_init(&priv->frontend);
|
||||
|
||||
atbm8830_i2c_gate_ctrl(&priv->frontend, 1);
|
||||
|
||||
return &priv->frontend;
|
||||
|
||||
error_out:
|
||||
dprintk("%s() error_out\n", __func__);
|
||||
kfree(priv);
|
||||
return NULL;
|
||||
|
||||
}
|
||||
EXPORT_SYMBOL(atbm8830_attach);
|
||||
|
||||
MODULE_DESCRIPTION("AltoBeam ATBM8830/8831 GB20600 demodulator driver");
|
||||
MODULE_AUTHOR("David T. L. Wong <[email protected]>");
|
||||
MODULE_LICENSE("GPL");
|
||||
76
drivers/media/dvb/frontends/atbm8830.h
Normal file
76
drivers/media/dvb/frontends/atbm8830.h
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Support for AltoBeam GB20600 (a.k.a DMB-TH) demodulator
|
||||
* ATBM8830, ATBM8831
|
||||
*
|
||||
* Copyright (C) 2009 David T.L. Wong <davidtlwong@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __ATBM8830_H__
|
||||
#define __ATBM8830_H__
|
||||
|
||||
#include <linux/dvb/frontend.h>
|
||||
#include <linux/i2c.h>
|
||||
|
||||
#define ATBM8830_PROD_8830 0
|
||||
#define ATBM8830_PROD_8831 1
|
||||
|
||||
struct atbm8830_config {
|
||||
|
||||
/* product type */
|
||||
u8 prod;
|
||||
|
||||
/* the demodulator's i2c address */
|
||||
u8 demod_address;
|
||||
|
||||
/* parallel or serial transport stream */
|
||||
u8 serial_ts;
|
||||
|
||||
/* transport stream clock output only when receving valid stream */
|
||||
u8 ts_clk_gated;
|
||||
|
||||
/* Decoder sample TS data at rising edge of clock */
|
||||
u8 ts_sampling_edge;
|
||||
|
||||
/* Oscillator clock frequency */
|
||||
u32 osc_clk_freq; /* in kHz */
|
||||
|
||||
/* IF frequency */
|
||||
u32 if_freq; /* in kHz */
|
||||
|
||||
/* Swap I/Q for zero IF */
|
||||
u8 zif_swap_iq;
|
||||
|
||||
/* Tuner AGC settings */
|
||||
u8 agc_min;
|
||||
u8 agc_max;
|
||||
u8 agc_hold_loop;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_DVB_ATBM8830) || \
|
||||
(defined(CONFIG_DVB_ATBM8830_MODULE) && defined(MODULE))
|
||||
extern struct dvb_frontend *atbm8830_attach(const struct atbm8830_config *config,
|
||||
struct i2c_adapter *i2c);
|
||||
#else
|
||||
static inline
|
||||
struct dvb_frontend *atbm8830_attach(const struct atbm8830_config *config,
|
||||
struct i2c_adapter *i2c) {
|
||||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
#endif /* CONFIG_DVB_ATBM8830 */
|
||||
|
||||
#endif /* __ATBM8830_H__ */
|
||||
75
drivers/media/dvb/frontends/atbm8830_priv.h
Normal file
75
drivers/media/dvb/frontends/atbm8830_priv.h
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Support for AltoBeam GB20600 (a.k.a DMB-TH) demodulator
|
||||
* ATBM8830, ATBM8831
|
||||
*
|
||||
* Copyright (C) 2009 David T.L. Wong <davidtlwong@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __ATBM8830_PRIV_H
|
||||
#define __ATBM8830_PRIV_H
|
||||
|
||||
struct atbm_state {
|
||||
struct i2c_adapter *i2c;
|
||||
/* configuration settings */
|
||||
const struct atbm8830_config *config;
|
||||
struct dvb_frontend frontend;
|
||||
};
|
||||
|
||||
#define REG_CHIP_ID 0x0000
|
||||
#define REG_TUNER_BASEBAND 0x0001
|
||||
#define REG_DEMOD_RUN 0x0004
|
||||
#define REG_DSP_RESET 0x0005
|
||||
#define REG_RAM_RESET 0x0006
|
||||
#define REG_ADC_RESET 0x0007
|
||||
#define REG_TSPORT_RESET 0x0008
|
||||
#define REG_BLKERR_POL 0x000C
|
||||
#define REG_I2C_GATE 0x0103
|
||||
#define REG_TS_SAMPLE_EDGE 0x0301
|
||||
#define REG_TS_PKT_LEN_204 0x0302
|
||||
#define REG_TS_PKT_LEN_AUTO 0x0303
|
||||
#define REG_TS_SERIAL 0x0305
|
||||
#define REG_TS_CLK_FREERUN 0x0306
|
||||
#define REG_TS_VALID_MODE 0x0307
|
||||
#define REG_TS_CLK_MODE 0x030B /* 1 for serial, 0 for parallel */
|
||||
|
||||
#define REG_TS_ERRBIT_USE 0x030C
|
||||
#define REG_LOCK_STATUS 0x030D
|
||||
#define REG_ADC_CONFIG 0x0602
|
||||
#define REG_CARRIER_OFFSET 0x0827 /* 0x0827-0x0829 little endian */
|
||||
#define REG_DETECTED_PN_MODE 0x082D
|
||||
#define REG_READ_LATCH 0x084D
|
||||
#define REG_IF_FREQ 0x0A00 /* 0x0A00-0x0A02 little endian */
|
||||
#define REG_OSC_CLK 0x0A03 /* 0x0A03-0x0A05 little endian */
|
||||
#define REG_BYPASS_CCI 0x0A06
|
||||
#define REG_ANALOG_LUMA_DETECTED 0x0A25
|
||||
#define REG_ANALOG_AUDIO_DETECTED 0x0A26
|
||||
#define REG_ANALOG_CHROMA_DETECTED 0x0A39
|
||||
#define REG_FRAME_ERR_CNT 0x0B04
|
||||
#define REG_USE_EXT_ADC 0x0C00
|
||||
#define REG_SWAP_I_Q 0x0C01
|
||||
#define REG_TPS_MANUAL 0x0D01
|
||||
#define REG_TPS_CONFIG 0x0D02
|
||||
#define REG_BYPASS_DEINTERLEAVER 0x0E00
|
||||
#define REG_AGC_TARGET 0x1003 /* 0x1003-0x1005 little endian */
|
||||
#define REG_AGC_MIN 0x1020
|
||||
#define REG_AGC_MAX 0x1023
|
||||
#define REG_AGC_LOCK 0x1027
|
||||
#define REG_AGC_PWM_VAL 0x1028 /* 0x1028-0x1029 little endian */
|
||||
#define REG_AGC_HOLD_LOOP 0x1031
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -23,7 +23,6 @@
|
|||
/* Developer notes:
|
||||
*
|
||||
* VBI support is not yet working
|
||||
* Saturation and hue setting are not yet working
|
||||
* Enough is implemented here for CVBS and S-Video inputs, but the actual
|
||||
* analog demodulator code isn't implemented (not needed for xc5000 since it
|
||||
* has its own demodulator and outputs CVBS)
|
||||
|
|
@ -236,8 +235,10 @@ static void setup_decoder_defaults(struct au8522_state *state, u8 input_mode)
|
|||
state->contrast = 0x79;
|
||||
au8522_writereg(state, AU8522_TVDEC_SATURATION_CB_REG00CH, 0x80);
|
||||
au8522_writereg(state, AU8522_TVDEC_SATURATION_CR_REG00DH, 0x80);
|
||||
state->saturation = 0x80;
|
||||
au8522_writereg(state, AU8522_TVDEC_HUE_H_REG00EH, 0x00);
|
||||
au8522_writereg(state, AU8522_TVDEC_HUE_L_REG00FH, 0x00);
|
||||
state->hue = 0x00;
|
||||
|
||||
/* Other decoder registers */
|
||||
au8522_writereg(state, AU8522_TVDEC_INT_MASK_REG010H, 0x00);
|
||||
|
|
@ -504,7 +505,19 @@ static int au8522_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
|
|||
ctrl->value);
|
||||
break;
|
||||
case V4L2_CID_SATURATION:
|
||||
state->saturation = ctrl->value;
|
||||
au8522_writereg(state, AU8522_TVDEC_SATURATION_CB_REG00CH,
|
||||
ctrl->value);
|
||||
au8522_writereg(state, AU8522_TVDEC_SATURATION_CR_REG00DH,
|
||||
ctrl->value);
|
||||
break;
|
||||
case V4L2_CID_HUE:
|
||||
state->hue = ctrl->value;
|
||||
au8522_writereg(state, AU8522_TVDEC_HUE_H_REG00EH,
|
||||
ctrl->value >> 8);
|
||||
au8522_writereg(state, AU8522_TVDEC_HUE_L_REG00FH,
|
||||
ctrl->value & 0xFF);
|
||||
break;
|
||||
case V4L2_CID_AUDIO_VOLUME:
|
||||
case V4L2_CID_AUDIO_BASS:
|
||||
case V4L2_CID_AUDIO_TREBLE:
|
||||
|
|
@ -534,7 +547,11 @@ static int au8522_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
|
|||
ctrl->value = state->contrast;
|
||||
break;
|
||||
case V4L2_CID_SATURATION:
|
||||
ctrl->value = state->saturation;
|
||||
break;
|
||||
case V4L2_CID_HUE:
|
||||
ctrl->value = state->hue;
|
||||
break;
|
||||
case V4L2_CID_AUDIO_VOLUME:
|
||||
case V4L2_CID_AUDIO_BASS:
|
||||
case V4L2_CID_AUDIO_TREBLE:
|
||||
|
|
@ -632,8 +649,9 @@ static int au8522_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
|
|||
case V4L2_CID_BRIGHTNESS:
|
||||
return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
|
||||
case V4L2_CID_SATURATION:
|
||||
return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
|
||||
case V4L2_CID_HUE:
|
||||
/* Not yet implemented */
|
||||
return v4l2_ctrl_query_fill(qc, -32768, 32768, 1, 0);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,6 +62,8 @@ struct au8522_state {
|
|||
u32 rev;
|
||||
u8 brightness;
|
||||
u8 contrast;
|
||||
u8 saturation;
|
||||
s16 hue;
|
||||
};
|
||||
|
||||
/* These are routines shared by both the VSB/QAM demodulator and the analog
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode)
|
|||
|
||||
outreg = 0;
|
||||
fifo_threshold = 1792;
|
||||
smo_mode = (dib7000p_read_word(state, 235) & 0x0010) | (1 << 1);
|
||||
smo_mode = (dib7000p_read_word(state, 235) & 0x0050) | (1 << 1);
|
||||
|
||||
dprintk( "setting output mode for demod %p to %d",
|
||||
&state->demod, mode);
|
||||
|
|
@ -162,18 +162,19 @@ static int dib7000p_set_diversity_in(struct dvb_frontend *demod, int onoff)
|
|||
if (state->div_force_off) {
|
||||
dprintk( "diversity combination deactivated - forced by COFDM parameters");
|
||||
onoff = 0;
|
||||
}
|
||||
dib7000p_write_word(state, 207, 0);
|
||||
} else
|
||||
dib7000p_write_word(state, 207, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0));
|
||||
|
||||
state->div_state = (u8)onoff;
|
||||
|
||||
if (onoff) {
|
||||
dib7000p_write_word(state, 204, 6);
|
||||
dib7000p_write_word(state, 205, 16);
|
||||
/* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */
|
||||
dib7000p_write_word(state, 207, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0));
|
||||
} else {
|
||||
dib7000p_write_word(state, 204, 1);
|
||||
dib7000p_write_word(state, 205, 0);
|
||||
dib7000p_write_word(state, 207, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -1188,7 +1189,7 @@ static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t *stat)
|
|||
*stat |= FE_HAS_VITERBI;
|
||||
if (lock & 0x0010)
|
||||
*stat |= FE_HAS_SYNC;
|
||||
if (lock & 0x0008)
|
||||
if ((lock & 0x0038) == 0x38)
|
||||
*stat |= FE_HAS_LOCK;
|
||||
|
||||
return 0;
|
||||
|
|
@ -1302,6 +1303,24 @@ struct i2c_adapter * dib7000p_get_i2c_master(struct dvb_frontend *demod, enum di
|
|||
}
|
||||
EXPORT_SYMBOL(dib7000p_get_i2c_master);
|
||||
|
||||
int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
|
||||
{
|
||||
struct dib7000p_state *state = fe->demodulator_priv;
|
||||
u16 val = dib7000p_read_word(state, 235) & 0xffef;
|
||||
val |= (onoff & 0x1) << 4;
|
||||
dprintk("PID filter enabled %d", onoff);
|
||||
return dib7000p_write_word(state, 235, val);
|
||||
}
|
||||
EXPORT_SYMBOL(dib7000p_pid_filter_ctrl);
|
||||
|
||||
int dib7000p_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
|
||||
{
|
||||
struct dib7000p_state *state = fe->demodulator_priv;
|
||||
dprintk("PID filter: index %x, PID %d, OnOff %d", id, pid, onoff);
|
||||
return dib7000p_write_word(state, 241 + id, onoff ? (1 << 13) | pid : 0);
|
||||
}
|
||||
EXPORT_SYMBOL(dib7000p_pid_filter);
|
||||
|
||||
int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[])
|
||||
{
|
||||
struct dib7000p_state st = { .i2c_adap = i2c };
|
||||
|
|
@ -1314,8 +1333,10 @@ int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defau
|
|||
/* designated i2c address */
|
||||
new_addr = (0x40 + k) << 1;
|
||||
st.i2c_addr = new_addr;
|
||||
dib7000p_write_word(&st, 1287, 0x0003); /* sram lead in, rdy */
|
||||
if (dib7000p_identify(&st) != 0) {
|
||||
st.i2c_addr = default_addr;
|
||||
dib7000p_write_word(&st, 1287, 0x0003); /* sram lead in, rdy */
|
||||
if (dib7000p_identify(&st) != 0) {
|
||||
dprintk("DiB7000P #%d: not identified\n", k);
|
||||
return -EIO;
|
||||
|
|
@ -1372,6 +1393,8 @@ struct dvb_frontend * dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr,
|
|||
demod->demodulator_priv = st;
|
||||
memcpy(&st->demod.ops, &dib7000p_ops, sizeof(struct dvb_frontend_ops));
|
||||
|
||||
dib7000p_write_word(st, 1287, 0x0003); /* sram lead in, rdy */
|
||||
|
||||
if (dib7000p_identify(st) != 0)
|
||||
goto error;
|
||||
|
||||
|
|
|
|||
|
|
@ -51,6 +51,8 @@ extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c,
|
|||
extern int dib7000p_set_gpio(struct dvb_frontend *, u8 num, u8 dir, u8 val);
|
||||
extern int dib7000p_set_wbd_ref(struct dvb_frontend *, u16 value);
|
||||
extern int dib7000pc_detection(struct i2c_adapter *i2c_adap);
|
||||
extern int dib7000p_pid_filter(struct dvb_frontend *, u8 id, u16 pid, u8 onoff);
|
||||
extern int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff);
|
||||
#else
|
||||
static inline
|
||||
struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr,
|
||||
|
|
@ -95,6 +97,17 @@ static inline int dib7000pc_detection(struct i2c_adapter *i2c_adap)
|
|||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
static inline int dib7000p_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
|
||||
{
|
||||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static inline int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, uint8_t onoff)
|
||||
{
|
||||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -954,7 +954,7 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear
|
|||
u8 guard, crate, constellation, timeI;
|
||||
u8 permu_seg[] = { 6, 5, 7, 4, 8, 3, 9, 2, 10, 1, 11, 0, 12 };
|
||||
u16 i, coeff[4], P_cfr_left_edge = 0, P_cfr_right_edge = 0, seg_mask13 = 0x1fff; // All 13 segments enabled
|
||||
const s16 *ncoeff, *ana_fe;
|
||||
const s16 *ncoeff = NULL, *ana_fe;
|
||||
u16 tmcc_pow = 0;
|
||||
u16 coff_pow = 0x2800;
|
||||
u16 init_prbs = 0xfff;
|
||||
|
|
@ -2121,7 +2121,7 @@ static int dib8000_read_snr(struct dvb_frontend *fe, u16 * snr)
|
|||
else
|
||||
result -= intlog10(2) * 10 * noise_exp - 100;
|
||||
|
||||
*snr = result / (1 << 24);
|
||||
*snr = result / ((1 << 24) / 10);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -2195,6 +2195,25 @@ struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *fe, enum dibx000
|
|||
|
||||
EXPORT_SYMBOL(dib8000_get_i2c_master);
|
||||
|
||||
int dib8000_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
|
||||
{
|
||||
struct dib8000_state *st = fe->demodulator_priv;
|
||||
u16 val = dib8000_read_word(st, 299) & 0xffef;
|
||||
val |= (onoff & 0x1) << 4;
|
||||
|
||||
dprintk("pid filter enabled %d", onoff);
|
||||
return dib8000_write_word(st, 299, val);
|
||||
}
|
||||
EXPORT_SYMBOL(dib8000_pid_filter_ctrl);
|
||||
|
||||
int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
|
||||
{
|
||||
struct dib8000_state *st = fe->demodulator_priv;
|
||||
dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff);
|
||||
return dib8000_write_word(st, 305 + id, onoff ? (1 << 13) | pid : 0);
|
||||
}
|
||||
EXPORT_SYMBOL(dib8000_pid_filter);
|
||||
|
||||
static const struct dvb_frontend_ops dib8000_ops = {
|
||||
.info = {
|
||||
.name = "DiBcom 8000 ISDB-T",
|
||||
|
|
|
|||
|
|
@ -44,6 +44,8 @@ extern int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u
|
|||
|
||||
extern int dib8000_set_gpio(struct dvb_frontend *, u8 num, u8 dir, u8 val);
|
||||
extern int dib8000_set_wbd_ref(struct dvb_frontend *, u16 value);
|
||||
extern int dib8000_pid_filter_ctrl(struct dvb_frontend *, u8 onoff);
|
||||
extern int dib8000_pid_filter(struct dvb_frontend *, u8 id, u16 pid, u8 onoff);
|
||||
#else
|
||||
static inline struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg)
|
||||
{
|
||||
|
|
@ -74,6 +76,18 @@ int dib8000_set_wbd_ref(struct dvb_frontend *fe, u16 value)
|
|||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
int dib8000_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
|
||||
{
|
||||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
|
||||
{
|
||||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
|||
1367
drivers/media/dvb/frontends/ds3000.c
Normal file
1367
drivers/media/dvb/frontends/ds3000.c
Normal file
File diff suppressed because it is too large
Load diff
45
drivers/media/dvb/frontends/ds3000.h
Normal file
45
drivers/media/dvb/frontends/ds3000.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
Montage Technology DS3000/TS2020 - DVBS/S2 Satellite demod/tuner driver
|
||||
Copyright (C) 2009 Konstantin Dimitrov <kosio.dimitrov@gmail.com>
|
||||
|
||||
Copyright (C) 2009 TurboSight.com
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef DS3000_H
|
||||
#define DS3000_H
|
||||
|
||||
#include <linux/dvb/frontend.h>
|
||||
|
||||
struct ds3000_config {
|
||||
/* the demodulator's i2c address */
|
||||
u8 demod_address;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_DVB_DS3000) || \
|
||||
(defined(CONFIG_DVB_DS3000_MODULE) && defined(MODULE))
|
||||
extern struct dvb_frontend *ds3000_attach(const struct ds3000_config *config,
|
||||
struct i2c_adapter *i2c);
|
||||
#else
|
||||
static inline
|
||||
struct dvb_frontend *ds3000_attach(const struct ds3000_config *config,
|
||||
struct i2c_adapter *i2c)
|
||||
{
|
||||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
#endif /* CONFIG_DVB_DS3000 */
|
||||
#endif /* DS3000_H */
|
||||
335
drivers/media/dvb/frontends/ec100.c
Normal file
335
drivers/media/dvb/frontends/ec100.c
Normal file
|
|
@ -0,0 +1,335 @@
|
|||
/*
|
||||
* E3C EC100 demodulator driver
|
||||
*
|
||||
* Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
|
||||
*
|
||||
* 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 "dvb_frontend.h"
|
||||
#include "ec100_priv.h"
|
||||
#include "ec100.h"
|
||||
|
||||
int ec100_debug;
|
||||
module_param_named(debug, ec100_debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
|
||||
|
||||
struct ec100_state {
|
||||
struct i2c_adapter *i2c;
|
||||
struct dvb_frontend frontend;
|
||||
struct ec100_config config;
|
||||
|
||||
u16 ber;
|
||||
};
|
||||
|
||||
/* write single register */
|
||||
static int ec100_write_reg(struct ec100_state *state, u8 reg, u8 val)
|
||||
{
|
||||
u8 buf[2] = {reg, val};
|
||||
struct i2c_msg msg = {
|
||||
.addr = state->config.demod_address,
|
||||
.flags = 0,
|
||||
.len = 2,
|
||||
.buf = buf};
|
||||
|
||||
if (i2c_transfer(state->i2c, &msg, 1) != 1) {
|
||||
warn("I2C write failed reg:%02x", reg);
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* read single register */
|
||||
static int ec100_read_reg(struct ec100_state *state, u8 reg, u8 *val)
|
||||
{
|
||||
struct i2c_msg msg[2] = {
|
||||
{
|
||||
.addr = state->config.demod_address,
|
||||
.flags = 0,
|
||||
.len = 1,
|
||||
.buf = ®
|
||||
}, {
|
||||
.addr = state->config.demod_address,
|
||||
.flags = I2C_M_RD,
|
||||
.len = 1,
|
||||
.buf = val
|
||||
}
|
||||
};
|
||||
|
||||
if (i2c_transfer(state->i2c, msg, 2) != 2) {
|
||||
warn("I2C read failed reg:%02x", reg);
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ec100_set_frontend(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_parameters *params)
|
||||
{
|
||||
struct ec100_state *state = fe->demodulator_priv;
|
||||
int ret;
|
||||
u8 tmp, tmp2;
|
||||
|
||||
deb_info("%s: freq:%d bw:%d\n", __func__, params->frequency,
|
||||
params->u.ofdm.bandwidth);
|
||||
|
||||
/* program tuner */
|
||||
if (fe->ops.tuner_ops.set_params)
|
||||
fe->ops.tuner_ops.set_params(fe, params);
|
||||
|
||||
ret = ec100_write_reg(state, 0x04, 0x06);
|
||||
if (ret)
|
||||
goto error;
|
||||
ret = ec100_write_reg(state, 0x67, 0x58);
|
||||
if (ret)
|
||||
goto error;
|
||||
ret = ec100_write_reg(state, 0x05, 0x18);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
/* reg/bw | 6 | 7 | 8
|
||||
-------+------+------+------
|
||||
A 0x1b | 0xa1 | 0xe7 | 0x2c
|
||||
A 0x1c | 0x55 | 0x63 | 0x72
|
||||
-------+------+------+------
|
||||
B 0x1b | 0xb7 | 0x00 | 0x49
|
||||
B 0x1c | 0x55 | 0x64 | 0x72 */
|
||||
|
||||
switch (params->u.ofdm.bandwidth) {
|
||||
case BANDWIDTH_6_MHZ:
|
||||
tmp = 0xb7;
|
||||
tmp2 = 0x55;
|
||||
break;
|
||||
case BANDWIDTH_7_MHZ:
|
||||
tmp = 0x00;
|
||||
tmp2 = 0x64;
|
||||
break;
|
||||
case BANDWIDTH_8_MHZ:
|
||||
default:
|
||||
tmp = 0x49;
|
||||
tmp2 = 0x72;
|
||||
}
|
||||
|
||||
ret = ec100_write_reg(state, 0x1b, tmp);
|
||||
if (ret)
|
||||
goto error;
|
||||
ret = ec100_write_reg(state, 0x1c, tmp2);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
ret = ec100_write_reg(state, 0x0c, 0xbb); /* if freq */
|
||||
if (ret)
|
||||
goto error;
|
||||
ret = ec100_write_reg(state, 0x0d, 0x31); /* if freq */
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
ret = ec100_write_reg(state, 0x08, 0x24);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
ret = ec100_write_reg(state, 0x00, 0x00); /* go */
|
||||
if (ret)
|
||||
goto error;
|
||||
ret = ec100_write_reg(state, 0x00, 0x20); /* go */
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
return ret;
|
||||
error:
|
||||
deb_info("%s: failed:%d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ec100_get_tune_settings(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_tune_settings *fesettings)
|
||||
{
|
||||
fesettings->min_delay_ms = 300;
|
||||
fesettings->step_size = 0;
|
||||
fesettings->max_drift = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ec100_read_status(struct dvb_frontend *fe, fe_status_t *status)
|
||||
{
|
||||
struct ec100_state *state = fe->demodulator_priv;
|
||||
int ret;
|
||||
u8 tmp;
|
||||
*status = 0;
|
||||
|
||||
ret = ec100_read_reg(state, 0x42, &tmp);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
if (tmp & 0x80) {
|
||||
/* bit7 set - have lock */
|
||||
*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI |
|
||||
FE_HAS_SYNC | FE_HAS_LOCK;
|
||||
} else {
|
||||
ret = ec100_read_reg(state, 0x01, &tmp);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
if (tmp & 0x10) {
|
||||
/* bit4 set - have signal */
|
||||
*status |= FE_HAS_SIGNAL;
|
||||
if (!(tmp & 0x01)) {
|
||||
/* bit0 clear - have ~valid signal */
|
||||
*status |= FE_HAS_CARRIER | FE_HAS_VITERBI;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
error:
|
||||
deb_info("%s: failed:%d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ec100_read_ber(struct dvb_frontend *fe, u32 *ber)
|
||||
{
|
||||
struct ec100_state *state = fe->demodulator_priv;
|
||||
int ret;
|
||||
u8 tmp, tmp2;
|
||||
u16 ber2;
|
||||
|
||||
*ber = 0;
|
||||
|
||||
ret = ec100_read_reg(state, 0x65, &tmp);
|
||||
if (ret)
|
||||
goto error;
|
||||
ret = ec100_read_reg(state, 0x66, &tmp2);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
ber2 = (tmp2 << 8) | tmp;
|
||||
|
||||
/* if counter overflow or clear */
|
||||
if (ber2 < state->ber)
|
||||
*ber = ber2;
|
||||
else
|
||||
*ber = ber2 - state->ber;
|
||||
|
||||
state->ber = ber2;
|
||||
|
||||
return ret;
|
||||
error:
|
||||
deb_info("%s: failed:%d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ec100_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
|
||||
{
|
||||
struct ec100_state *state = fe->demodulator_priv;
|
||||
int ret;
|
||||
u8 tmp;
|
||||
|
||||
ret = ec100_read_reg(state, 0x24, &tmp);
|
||||
if (ret) {
|
||||
*strength = 0;
|
||||
goto error;
|
||||
}
|
||||
|
||||
*strength = ((tmp << 8) | tmp);
|
||||
|
||||
return ret;
|
||||
error:
|
||||
deb_info("%s: failed:%d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ec100_read_snr(struct dvb_frontend *fe, u16 *snr)
|
||||
{
|
||||
*snr = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ec100_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
|
||||
{
|
||||
*ucblocks = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ec100_release(struct dvb_frontend *fe)
|
||||
{
|
||||
struct ec100_state *state = fe->demodulator_priv;
|
||||
kfree(state);
|
||||
}
|
||||
|
||||
static struct dvb_frontend_ops ec100_ops;
|
||||
|
||||
struct dvb_frontend *ec100_attach(const struct ec100_config *config,
|
||||
struct i2c_adapter *i2c)
|
||||
{
|
||||
int ret;
|
||||
struct ec100_state *state = NULL;
|
||||
u8 tmp;
|
||||
|
||||
/* allocate memory for the internal state */
|
||||
state = kzalloc(sizeof(struct ec100_state), GFP_KERNEL);
|
||||
if (state == NULL)
|
||||
goto error;
|
||||
|
||||
/* setup the state */
|
||||
state->i2c = i2c;
|
||||
memcpy(&state->config, config, sizeof(struct ec100_config));
|
||||
|
||||
/* check if the demod is there */
|
||||
ret = ec100_read_reg(state, 0x33, &tmp);
|
||||
if (ret || tmp != 0x0b)
|
||||
goto error;
|
||||
|
||||
/* create dvb_frontend */
|
||||
memcpy(&state->frontend.ops, &ec100_ops,
|
||||
sizeof(struct dvb_frontend_ops));
|
||||
state->frontend.demodulator_priv = state;
|
||||
|
||||
return &state->frontend;
|
||||
error:
|
||||
kfree(state);
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(ec100_attach);
|
||||
|
||||
static struct dvb_frontend_ops ec100_ops = {
|
||||
.info = {
|
||||
.name = "E3C EC100 DVB-T",
|
||||
.type = FE_OFDM,
|
||||
.caps =
|
||||
FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
|
||||
FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
|
||||
FE_CAN_QPSK | FE_CAN_QAM_16 |
|
||||
FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
|
||||
FE_CAN_TRANSMISSION_MODE_AUTO |
|
||||
FE_CAN_GUARD_INTERVAL_AUTO |
|
||||
FE_CAN_HIERARCHY_AUTO |
|
||||
FE_CAN_MUTE_TS
|
||||
},
|
||||
|
||||
.release = ec100_release,
|
||||
.set_frontend = ec100_set_frontend,
|
||||
.get_tune_settings = ec100_get_tune_settings,
|
||||
.read_status = ec100_read_status,
|
||||
.read_ber = ec100_read_ber,
|
||||
.read_signal_strength = ec100_read_signal_strength,
|
||||
.read_snr = ec100_read_snr,
|
||||
.read_ucblocks = ec100_read_ucblocks,
|
||||
};
|
||||
|
||||
MODULE_AUTHOR("Antti Palosaari <[email protected]>");
|
||||
MODULE_DESCRIPTION("E3C EC100 DVB-T demodulator driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
46
drivers/media/dvb/frontends/ec100.h
Normal file
46
drivers/media/dvb/frontends/ec100.h
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* E3C EC100 demodulator driver
|
||||
*
|
||||
* Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef EC100_H
|
||||
#define EC100_H
|
||||
|
||||
#include <linux/dvb/frontend.h>
|
||||
|
||||
struct ec100_config {
|
||||
/* demodulator's I2C address */
|
||||
u8 demod_address;
|
||||
};
|
||||
|
||||
|
||||
#if defined(CONFIG_DVB_EC100) || \
|
||||
(defined(CONFIG_DVB_EC100_MODULE) && defined(MODULE))
|
||||
extern struct dvb_frontend *ec100_attach(const struct ec100_config *config,
|
||||
struct i2c_adapter *i2c);
|
||||
#else
|
||||
static inline struct dvb_frontend *ec100_attach(
|
||||
const struct ec100_config *config, struct i2c_adapter *i2c)
|
||||
{
|
||||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* EC100_H */
|
||||
39
drivers/media/dvb/frontends/ec100_priv.h
Normal file
39
drivers/media/dvb/frontends/ec100_priv.h
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* E3C EC100 demodulator driver
|
||||
*
|
||||
* Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef EC100_PRIV
|
||||
#define EC100_PRIV
|
||||
|
||||
#define LOG_PREFIX "ec100"
|
||||
|
||||
#define dprintk(var, level, args...) \
|
||||
do { if ((var & level)) printk(args); } while (0)
|
||||
|
||||
#define deb_info(args...) dprintk(ec100_debug, 0x01, args)
|
||||
|
||||
#undef err
|
||||
#define err(f, arg...) printk(KERN_ERR LOG_PREFIX": " f "\n" , ## arg)
|
||||
#undef info
|
||||
#define info(f, arg...) printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg)
|
||||
#undef warn
|
||||
#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
|
||||
|
||||
#endif /* EC100_PRIV */
|
||||
|
|
@ -44,7 +44,15 @@ struct s5h1409_state {
|
|||
int if_freq;
|
||||
|
||||
u32 is_qam_locked;
|
||||
u32 qam_state;
|
||||
|
||||
/* QAM tuning state goes through the following state transitions */
|
||||
#define QAM_STATE_UNTUNED 0
|
||||
#define QAM_STATE_TUNING_STARTED 1
|
||||
#define QAM_STATE_INTERLEAVE_SET 2
|
||||
#define QAM_STATE_QAM_OPTIMIZED_L1 3
|
||||
#define QAM_STATE_QAM_OPTIMIZED_L2 4
|
||||
#define QAM_STATE_QAM_OPTIMIZED_L3 5
|
||||
u8 qam_state;
|
||||
};
|
||||
|
||||
static int debug;
|
||||
|
|
@ -347,7 +355,7 @@ static int s5h1409_softreset(struct dvb_frontend *fe)
|
|||
s5h1409_writereg(state, 0xf5, 0);
|
||||
s5h1409_writereg(state, 0xf5, 1);
|
||||
state->is_qam_locked = 0;
|
||||
state->qam_state = 0;
|
||||
state->qam_state = QAM_STATE_UNTUNED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -474,6 +482,59 @@ static void s5h1409_set_qam_amhum_mode(struct dvb_frontend *fe)
|
|||
struct s5h1409_state *state = fe->demodulator_priv;
|
||||
u16 reg;
|
||||
|
||||
if (state->qam_state < QAM_STATE_INTERLEAVE_SET) {
|
||||
/* We should not perform amhum optimization until
|
||||
the interleave mode has been configured */
|
||||
return;
|
||||
}
|
||||
|
||||
if (state->qam_state == QAM_STATE_QAM_OPTIMIZED_L3) {
|
||||
/* We've already reached the maximum optimization level, so
|
||||
dont bother banging on the status registers */
|
||||
return;
|
||||
}
|
||||
|
||||
/* QAM EQ lock check */
|
||||
reg = s5h1409_readreg(state, 0xf0);
|
||||
|
||||
if ((reg >> 13) & 0x1) {
|
||||
reg &= 0xff;
|
||||
|
||||
s5h1409_writereg(state, 0x96, 0x000c);
|
||||
if (reg < 0x68) {
|
||||
if (state->qam_state < QAM_STATE_QAM_OPTIMIZED_L3) {
|
||||
dprintk("%s() setting QAM state to OPT_L3\n",
|
||||
__func__);
|
||||
s5h1409_writereg(state, 0x93, 0x3130);
|
||||
s5h1409_writereg(state, 0x9e, 0x2836);
|
||||
state->qam_state = QAM_STATE_QAM_OPTIMIZED_L3;
|
||||
}
|
||||
} else {
|
||||
if (state->qam_state < QAM_STATE_QAM_OPTIMIZED_L2) {
|
||||
dprintk("%s() setting QAM state to OPT_L2\n",
|
||||
__func__);
|
||||
s5h1409_writereg(state, 0x93, 0x3332);
|
||||
s5h1409_writereg(state, 0x9e, 0x2c37);
|
||||
state->qam_state = QAM_STATE_QAM_OPTIMIZED_L2;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
if (state->qam_state < QAM_STATE_QAM_OPTIMIZED_L1) {
|
||||
dprintk("%s() setting QAM state to OPT_L1\n", __func__);
|
||||
s5h1409_writereg(state, 0x96, 0x0008);
|
||||
s5h1409_writereg(state, 0x93, 0x3332);
|
||||
s5h1409_writereg(state, 0x9e, 0x2c37);
|
||||
state->qam_state = QAM_STATE_QAM_OPTIMIZED_L1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void s5h1409_set_qam_amhum_mode_legacy(struct dvb_frontend *fe)
|
||||
{
|
||||
struct s5h1409_state *state = fe->demodulator_priv;
|
||||
u16 reg;
|
||||
|
||||
if (state->is_qam_locked)
|
||||
return;
|
||||
|
||||
|
|
@ -506,6 +567,44 @@ static void s5h1409_set_qam_interleave_mode(struct dvb_frontend *fe)
|
|||
struct s5h1409_state *state = fe->demodulator_priv;
|
||||
u16 reg, reg1, reg2;
|
||||
|
||||
if (state->qam_state >= QAM_STATE_INTERLEAVE_SET) {
|
||||
/* We've done the optimization already */
|
||||
return;
|
||||
}
|
||||
|
||||
reg = s5h1409_readreg(state, 0xf1);
|
||||
|
||||
/* Master lock */
|
||||
if ((reg >> 15) & 0x1) {
|
||||
if (state->qam_state == QAM_STATE_UNTUNED ||
|
||||
state->qam_state == QAM_STATE_TUNING_STARTED) {
|
||||
dprintk("%s() setting QAM state to INTERLEAVE_SET\n",
|
||||
__func__);
|
||||
reg1 = s5h1409_readreg(state, 0xb2);
|
||||
reg2 = s5h1409_readreg(state, 0xad);
|
||||
|
||||
s5h1409_writereg(state, 0x96, 0x0020);
|
||||
s5h1409_writereg(state, 0xad,
|
||||
(((reg1 & 0xf000) >> 4) | (reg2 & 0xf0ff)));
|
||||
state->qam_state = QAM_STATE_INTERLEAVE_SET;
|
||||
}
|
||||
} else {
|
||||
if (state->qam_state == QAM_STATE_UNTUNED) {
|
||||
dprintk("%s() setting QAM state to TUNING_STARTED\n",
|
||||
__func__);
|
||||
s5h1409_writereg(state, 0x96, 0x08);
|
||||
s5h1409_writereg(state, 0xab,
|
||||
s5h1409_readreg(state, 0xab) | 0x1001);
|
||||
state->qam_state = QAM_STATE_TUNING_STARTED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void s5h1409_set_qam_interleave_mode_legacy(struct dvb_frontend *fe)
|
||||
{
|
||||
struct s5h1409_state *state = fe->demodulator_priv;
|
||||
u16 reg, reg1, reg2;
|
||||
|
||||
reg = s5h1409_readreg(state, 0xf1);
|
||||
|
||||
/* Master lock */
|
||||
|
|
@ -553,16 +652,24 @@ static int s5h1409_set_frontend(struct dvb_frontend *fe,
|
|||
fe->ops.i2c_gate_ctrl(fe, 0);
|
||||
}
|
||||
|
||||
/* Optimize the demod for QAM */
|
||||
if (p->u.vsb.modulation != VSB_8) {
|
||||
s5h1409_set_qam_amhum_mode(fe);
|
||||
s5h1409_set_qam_interleave_mode(fe);
|
||||
}
|
||||
|
||||
/* Issue a reset to the demod so it knows to resync against the
|
||||
newly tuned frequency */
|
||||
s5h1409_softreset(fe);
|
||||
|
||||
/* Optimize the demod for QAM */
|
||||
if (state->current_modulation != VSB_8) {
|
||||
/* This almost certainly applies to all boards, but for now
|
||||
only do it for the HVR-1600. Once the other boards are
|
||||
tested, the "legacy" versions can just go away */
|
||||
if (state->config->hvr1600_opt == S5H1409_HVR1600_OPTIMIZE) {
|
||||
s5h1409_set_qam_interleave_mode(fe);
|
||||
s5h1409_set_qam_amhum_mode(fe);
|
||||
} else {
|
||||
s5h1409_set_qam_amhum_mode_legacy(fe);
|
||||
s5h1409_set_qam_interleave_mode_legacy(fe);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -614,6 +721,21 @@ static int s5h1409_init(struct dvb_frontend *fe)
|
|||
/* The datasheet says that after initialisation, VSB is default */
|
||||
state->current_modulation = VSB_8;
|
||||
|
||||
/* Optimize for the HVR-1600 if appropriate. Note that some of these
|
||||
may get folded into the generic case after testing with other
|
||||
devices */
|
||||
if (state->config->hvr1600_opt == S5H1409_HVR1600_OPTIMIZE) {
|
||||
/* VSB AGC REF */
|
||||
s5h1409_writereg(state, 0x09, 0x0050);
|
||||
|
||||
/* Unknown but Windows driver does it... */
|
||||
s5h1409_writereg(state, 0x21, 0x0001);
|
||||
s5h1409_writereg(state, 0x50, 0x030e);
|
||||
|
||||
/* QAM AGC REF */
|
||||
s5h1409_writereg(state, 0x82, 0x0800);
|
||||
}
|
||||
|
||||
if (state->config->output_mode == S5H1409_SERIAL_OUTPUT)
|
||||
s5h1409_writereg(state, 0xab,
|
||||
s5h1409_readreg(state, 0xab) | 0x100); /* Serial */
|
||||
|
|
@ -641,6 +763,17 @@ static int s5h1409_read_status(struct dvb_frontend *fe, fe_status_t *status)
|
|||
|
||||
*status = 0;
|
||||
|
||||
/* Optimize the demod for QAM */
|
||||
if (state->current_modulation != VSB_8) {
|
||||
/* This almost certainly applies to all boards, but for now
|
||||
only do it for the HVR-1600. Once the other boards are
|
||||
tested, the "legacy" versions can just go away */
|
||||
if (state->config->hvr1600_opt == S5H1409_HVR1600_OPTIMIZE) {
|
||||
s5h1409_set_qam_interleave_mode(fe);
|
||||
s5h1409_set_qam_amhum_mode(fe);
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the demodulator status */
|
||||
reg = s5h1409_readreg(state, 0xf1);
|
||||
if (reg & 0x1000)
|
||||
|
|
|
|||
|
|
@ -57,6 +57,13 @@ struct s5h1409_config {
|
|||
#define S5H1409_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK 2
|
||||
#define S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK 3
|
||||
u16 mpeg_timing;
|
||||
|
||||
/* HVR-1600 optimizations (to better work with MXL5005s)
|
||||
Note: some of these are likely to be folded into the generic driver
|
||||
after being regression tested with other boards */
|
||||
#define S5H1409_HVR1600_NOOPTIMIZE 0
|
||||
#define S5H1409_HVR1600_OPTIMIZE 1
|
||||
u8 hvr1600_opt;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_DVB_S5H1409) || (defined(CONFIG_DVB_S5H1409_MODULE) \
|
||||
|
|
|
|||
138
drivers/media/dvb/frontends/stb6100_proc.h
Normal file
138
drivers/media/dvb/frontends/stb6100_proc.h
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
STB6100 Silicon Tuner wrapper
|
||||
Copyright (C)2009 Igor M. Liplianin (liplianin@me.by)
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
static int stb6100_get_freq(struct dvb_frontend *fe, u32 *frequency)
|
||||
{
|
||||
struct dvb_frontend_ops *frontend_ops = NULL;
|
||||
struct dvb_tuner_ops *tuner_ops = NULL;
|
||||
struct tuner_state state;
|
||||
int err = 0;
|
||||
|
||||
if (&fe->ops)
|
||||
frontend_ops = &fe->ops;
|
||||
if (&frontend_ops->tuner_ops)
|
||||
tuner_ops = &frontend_ops->tuner_ops;
|
||||
if (tuner_ops->get_state) {
|
||||
if (frontend_ops->i2c_gate_ctrl)
|
||||
frontend_ops->i2c_gate_ctrl(fe, 1);
|
||||
|
||||
err = tuner_ops->get_state(fe, DVBFE_TUNER_FREQUENCY, &state);
|
||||
if (err < 0) {
|
||||
printk(KERN_ERR "%s: Invalid parameter\n", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (frontend_ops->i2c_gate_ctrl)
|
||||
frontend_ops->i2c_gate_ctrl(fe, 0);
|
||||
|
||||
*frequency = state.frequency;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stb6100_set_freq(struct dvb_frontend *fe, u32 frequency)
|
||||
{
|
||||
struct dvb_frontend_ops *frontend_ops = NULL;
|
||||
struct dvb_tuner_ops *tuner_ops = NULL;
|
||||
struct tuner_state state;
|
||||
int err = 0;
|
||||
|
||||
state.frequency = frequency;
|
||||
if (&fe->ops)
|
||||
frontend_ops = &fe->ops;
|
||||
if (&frontend_ops->tuner_ops)
|
||||
tuner_ops = &frontend_ops->tuner_ops;
|
||||
if (tuner_ops->set_state) {
|
||||
if (frontend_ops->i2c_gate_ctrl)
|
||||
frontend_ops->i2c_gate_ctrl(fe, 1);
|
||||
|
||||
err = tuner_ops->set_state(fe, DVBFE_TUNER_FREQUENCY, &state);
|
||||
if (err < 0) {
|
||||
printk(KERN_ERR "%s: Invalid parameter\n", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (frontend_ops->i2c_gate_ctrl)
|
||||
frontend_ops->i2c_gate_ctrl(fe, 0);
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stb6100_get_bandw(struct dvb_frontend *fe, u32 *bandwidth)
|
||||
{
|
||||
struct dvb_frontend_ops *frontend_ops = NULL;
|
||||
struct dvb_tuner_ops *tuner_ops = NULL;
|
||||
struct tuner_state state;
|
||||
int err = 0;
|
||||
|
||||
if (&fe->ops)
|
||||
frontend_ops = &fe->ops;
|
||||
if (&frontend_ops->tuner_ops)
|
||||
tuner_ops = &frontend_ops->tuner_ops;
|
||||
if (tuner_ops->get_state) {
|
||||
if (frontend_ops->i2c_gate_ctrl)
|
||||
frontend_ops->i2c_gate_ctrl(fe, 1);
|
||||
|
||||
err = tuner_ops->get_state(fe, DVBFE_TUNER_BANDWIDTH, &state);
|
||||
if (err < 0) {
|
||||
printk(KERN_ERR "%s: Invalid parameter\n", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (frontend_ops->i2c_gate_ctrl)
|
||||
frontend_ops->i2c_gate_ctrl(fe, 0);
|
||||
|
||||
*bandwidth = state.bandwidth;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stb6100_set_bandw(struct dvb_frontend *fe, u32 bandwidth)
|
||||
{
|
||||
struct dvb_frontend_ops *frontend_ops = NULL;
|
||||
struct dvb_tuner_ops *tuner_ops = NULL;
|
||||
struct tuner_state state;
|
||||
int err = 0;
|
||||
|
||||
state.bandwidth = bandwidth;
|
||||
if (&fe->ops)
|
||||
frontend_ops = &fe->ops;
|
||||
if (&frontend_ops->tuner_ops)
|
||||
tuner_ops = &frontend_ops->tuner_ops;
|
||||
if (tuner_ops->set_state) {
|
||||
if (frontend_ops->i2c_gate_ctrl)
|
||||
frontend_ops->i2c_gate_ctrl(fe, 1);
|
||||
|
||||
err = tuner_ops->set_state(fe, DVBFE_TUNER_BANDWIDTH, &state);
|
||||
if (err < 0) {
|
||||
printk(KERN_ERR "%s: Invalid parameter\n", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (frontend_ops->i2c_gate_ctrl)
|
||||
frontend_ops->i2c_gate_ctrl(fe, 0);
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -36,6 +36,7 @@ struct stv0900_reg {
|
|||
|
||||
struct stv0900_config {
|
||||
u8 demod_address;
|
||||
u8 demod_mode;
|
||||
u32 xtal;
|
||||
u8 clkmode;/* 0 for CLKI, 2 for XTALI */
|
||||
|
||||
|
|
@ -48,6 +49,8 @@ struct stv0900_config {
|
|||
u8 tun2_maddress;
|
||||
u8 tun1_adc;/* 1 for stv6110, 2 for stb6100 */
|
||||
u8 tun2_adc;
|
||||
/* Set device param to start dma */
|
||||
int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured);
|
||||
};
|
||||
|
||||
#if defined(CONFIG_DVB_STV0900) || (defined(CONFIG_DVB_STV0900_MODULE) \
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -141,85 +141,228 @@ struct stv0900_short_frames_car_loop_optim {
|
|||
|
||||
};
|
||||
|
||||
struct stv0900_short_frames_car_loop_optim_vs_mod {
|
||||
enum fe_stv0900_modulation modulation;
|
||||
u8 car_loop_2; /* SR<3msps */
|
||||
u8 car_loop_5; /* 3<SR<=7msps */
|
||||
u8 car_loop_10; /* 7<SR<=15msps */
|
||||
u8 car_loop_20; /* 10<SR<=25msps */
|
||||
u8 car_loop_30; /* 10<SR<=45msps */
|
||||
};
|
||||
|
||||
/* Cut 1.x Tracking carrier loop carrier QPSK 1/2 to 8PSK 9/10 long Frame */
|
||||
static const struct stv0900_car_loop_optim FE_STV0900_S2CarLoop[14] = {
|
||||
/*Modcod 2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */
|
||||
{ STV0900_QPSK_12, 0x1C, 0x0D, 0x1B, 0x2C, 0x3A, 0x1C, 0x2A, 0x3B, 0x2A, 0x1B },
|
||||
{ STV0900_QPSK_35, 0x2C, 0x0D, 0x2B, 0x2C, 0x3A, 0x0C, 0x3A, 0x2B, 0x2A, 0x0B },
|
||||
{ STV0900_QPSK_23, 0x2C, 0x0D, 0x2B, 0x2C, 0x0B, 0x0C, 0x3A, 0x1B, 0x2A, 0x3A },
|
||||
{ STV0900_QPSK_34, 0x3C, 0x0D, 0x3B, 0x1C, 0x0B, 0x3B, 0x3A, 0x0B, 0x2A, 0x3A },
|
||||
{ STV0900_QPSK_45, 0x3C, 0x0D, 0x3B, 0x1C, 0x0B, 0x3B, 0x3A, 0x0B, 0x2A, 0x3A },
|
||||
{ STV0900_QPSK_56, 0x0D, 0x0D, 0x3B, 0x1C, 0x0B, 0x3B, 0x3A, 0x0B, 0x2A, 0x3A },
|
||||
{ STV0900_QPSK_89, 0x0D, 0x0D, 0x3B, 0x1C, 0x1B, 0x3B, 0x3A, 0x0B, 0x2A, 0x3A },
|
||||
{ STV0900_QPSK_910, 0x1D, 0x0D, 0x3B, 0x1C, 0x1B, 0x3B, 0x3A, 0x0B, 0x2A, 0x3A },
|
||||
{ STV0900_8PSK_35, 0x29, 0x3B, 0x09, 0x2B, 0x38, 0x0B, 0x18, 0x1A, 0x08, 0x0A },
|
||||
{ STV0900_8PSK_23, 0x0A, 0x3B, 0x29, 0x2B, 0x19, 0x0B, 0x38, 0x1A, 0x18, 0x0A },
|
||||
{ STV0900_8PSK_34, 0x3A, 0x3B, 0x2A, 0x2B, 0x39, 0x0B, 0x19, 0x1A, 0x38, 0x0A },
|
||||
{ STV0900_8PSK_56, 0x1B, 0x3B, 0x0B, 0x2B, 0x1A, 0x0B, 0x39, 0x1A, 0x19, 0x0A },
|
||||
{ STV0900_8PSK_89, 0x3B, 0x3B, 0x0B, 0x2B, 0x2A, 0x0B, 0x39, 0x1A, 0x29, 0x39 },
|
||||
{ STV0900_8PSK_910, 0x3B, 0x3B, 0x0B, 0x2B, 0x2A, 0x0B, 0x39, 0x1A, 0x29, 0x39 }
|
||||
static const struct stv0900_car_loop_optim FE_STV0900_S2CarLoop[14] = {
|
||||
/*Modcod 2MPon 2MPoff 5MPon 5MPoff 10MPon
|
||||
10MPoff 20MPon 20MPoff 30MPon 30MPoff */
|
||||
{ STV0900_QPSK_12, 0x1C, 0x0D, 0x1B, 0x2C, 0x3A,
|
||||
0x1C, 0x2A, 0x3B, 0x2A, 0x1B },
|
||||
{ STV0900_QPSK_35, 0x2C, 0x0D, 0x2B, 0x2C, 0x3A,
|
||||
0x0C, 0x3A, 0x2B, 0x2A, 0x0B },
|
||||
{ STV0900_QPSK_23, 0x2C, 0x0D, 0x2B, 0x2C, 0x0B,
|
||||
0x0C, 0x3A, 0x1B, 0x2A, 0x3A },
|
||||
{ STV0900_QPSK_34, 0x3C, 0x0D, 0x3B, 0x1C, 0x0B,
|
||||
0x3B, 0x3A, 0x0B, 0x2A, 0x3A },
|
||||
{ STV0900_QPSK_45, 0x3C, 0x0D, 0x3B, 0x1C, 0x0B,
|
||||
0x3B, 0x3A, 0x0B, 0x2A, 0x3A },
|
||||
{ STV0900_QPSK_56, 0x0D, 0x0D, 0x3B, 0x1C, 0x0B,
|
||||
0x3B, 0x3A, 0x0B, 0x2A, 0x3A },
|
||||
{ STV0900_QPSK_89, 0x0D, 0x0D, 0x3B, 0x1C, 0x1B,
|
||||
0x3B, 0x3A, 0x0B, 0x2A, 0x3A },
|
||||
{ STV0900_QPSK_910, 0x1D, 0x0D, 0x3B, 0x1C, 0x1B,
|
||||
0x3B, 0x3A, 0x0B, 0x2A, 0x3A },
|
||||
{ STV0900_8PSK_35, 0x29, 0x3B, 0x09, 0x2B, 0x38,
|
||||
0x0B, 0x18, 0x1A, 0x08, 0x0A },
|
||||
{ STV0900_8PSK_23, 0x0A, 0x3B, 0x29, 0x2B, 0x19,
|
||||
0x0B, 0x38, 0x1A, 0x18, 0x0A },
|
||||
{ STV0900_8PSK_34, 0x3A, 0x3B, 0x2A, 0x2B, 0x39,
|
||||
0x0B, 0x19, 0x1A, 0x38, 0x0A },
|
||||
{ STV0900_8PSK_56, 0x1B, 0x3B, 0x0B, 0x2B, 0x1A,
|
||||
0x0B, 0x39, 0x1A, 0x19, 0x0A },
|
||||
{ STV0900_8PSK_89, 0x3B, 0x3B, 0x0B, 0x2B, 0x2A,
|
||||
0x0B, 0x39, 0x1A, 0x29, 0x39 },
|
||||
{ STV0900_8PSK_910, 0x3B, 0x3B, 0x0B, 0x2B, 0x2A,
|
||||
0x0B, 0x39, 0x1A, 0x29, 0x39 }
|
||||
};
|
||||
|
||||
|
||||
/* Cut 2.0 Tracking carrier loop carrier QPSK 1/2 to 8PSK 9/10 long Frame */
|
||||
static const struct stv0900_car_loop_optim FE_STV0900_S2CarLoopCut20[14] = {
|
||||
/* Modcod 2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */
|
||||
{ STV0900_QPSK_12, 0x1F, 0x3F, 0x1E, 0x3F, 0x3D, 0x1F, 0x3D, 0x3E, 0x3D, 0x1E },
|
||||
{ STV0900_QPSK_35, 0x2F, 0x3F, 0x2E, 0x2F, 0x3D, 0x0F, 0x0E, 0x2E, 0x3D, 0x0E },
|
||||
{ STV0900_QPSK_23, 0x2F, 0x3F, 0x2E, 0x2F, 0x0E, 0x0F, 0x0E, 0x1E, 0x3D, 0x3D },
|
||||
{ STV0900_QPSK_34, 0x3F, 0x3F, 0x3E, 0x1F, 0x0E, 0x3E, 0x0E, 0x1E, 0x3D, 0x3D },
|
||||
{ STV0900_QPSK_45, 0x3F, 0x3F, 0x3E, 0x1F, 0x0E, 0x3E, 0x0E, 0x1E, 0x3D, 0x3D },
|
||||
{ STV0900_QPSK_56, 0x3F, 0x3F, 0x3E, 0x1F, 0x0E, 0x3E, 0x0E, 0x1E, 0x3D, 0x3D },
|
||||
{ STV0900_QPSK_89, 0x3F, 0x3F, 0x3E, 0x1F, 0x1E, 0x3E, 0x0E, 0x1E, 0x3D, 0x3D },
|
||||
{ STV0900_QPSK_910, 0x3F, 0x3F, 0x3E, 0x1F, 0x1E, 0x3E, 0x0E, 0x1E, 0x3D, 0x3D },
|
||||
{ STV0900_8PSK_35, 0x3c, 0x0c, 0x1c, 0x3b, 0x0c, 0x3b, 0x2b, 0x2b, 0x1b, 0x2b },
|
||||
{ STV0900_8PSK_23, 0x1d, 0x0c, 0x3c, 0x0c, 0x2c, 0x3b, 0x0c, 0x2b, 0x2b, 0x2b },
|
||||
{ STV0900_8PSK_34, 0x0e, 0x1c, 0x3d, 0x0c, 0x0d, 0x3b, 0x2c, 0x3b, 0x0c, 0x2b },
|
||||
{ STV0900_8PSK_56, 0x2e, 0x3e, 0x1e, 0x2e, 0x2d, 0x1e, 0x3c, 0x2d, 0x2c, 0x1d },
|
||||
{ STV0900_8PSK_89, 0x3e, 0x3e, 0x1e, 0x2e, 0x3d, 0x1e, 0x0d, 0x2d, 0x3c, 0x1d },
|
||||
{ STV0900_8PSK_910, 0x3e, 0x3e, 0x1e, 0x2e, 0x3d, 0x1e, 0x1d, 0x2d, 0x0d, 0x1d }
|
||||
static const struct stv0900_car_loop_optim FE_STV0900_S2CarLoopCut20[14] = {
|
||||
/* Modcod 2MPon 2MPoff 5MPon 5MPoff 10MPon
|
||||
10MPoff 20MPon 20MPoff 30MPon 30MPoff */
|
||||
{ STV0900_QPSK_12, 0x1F, 0x3F, 0x1E, 0x3F, 0x3D,
|
||||
0x1F, 0x3D, 0x3E, 0x3D, 0x1E },
|
||||
{ STV0900_QPSK_35, 0x2F, 0x3F, 0x2E, 0x2F, 0x3D,
|
||||
0x0F, 0x0E, 0x2E, 0x3D, 0x0E },
|
||||
{ STV0900_QPSK_23, 0x2F, 0x3F, 0x2E, 0x2F, 0x0E,
|
||||
0x0F, 0x0E, 0x1E, 0x3D, 0x3D },
|
||||
{ STV0900_QPSK_34, 0x3F, 0x3F, 0x3E, 0x1F, 0x0E,
|
||||
0x3E, 0x0E, 0x1E, 0x3D, 0x3D },
|
||||
{ STV0900_QPSK_45, 0x3F, 0x3F, 0x3E, 0x1F, 0x0E,
|
||||
0x3E, 0x0E, 0x1E, 0x3D, 0x3D },
|
||||
{ STV0900_QPSK_56, 0x3F, 0x3F, 0x3E, 0x1F, 0x0E,
|
||||
0x3E, 0x0E, 0x1E, 0x3D, 0x3D },
|
||||
{ STV0900_QPSK_89, 0x3F, 0x3F, 0x3E, 0x1F, 0x1E,
|
||||
0x3E, 0x0E, 0x1E, 0x3D, 0x3D },
|
||||
{ STV0900_QPSK_910, 0x3F, 0x3F, 0x3E, 0x1F, 0x1E,
|
||||
0x3E, 0x0E, 0x1E, 0x3D, 0x3D },
|
||||
{ STV0900_8PSK_35, 0x3c, 0x0c, 0x1c, 0x3b, 0x0c,
|
||||
0x3b, 0x2b, 0x2b, 0x1b, 0x2b },
|
||||
{ STV0900_8PSK_23, 0x1d, 0x0c, 0x3c, 0x0c, 0x2c,
|
||||
0x3b, 0x0c, 0x2b, 0x2b, 0x2b },
|
||||
{ STV0900_8PSK_34, 0x0e, 0x1c, 0x3d, 0x0c, 0x0d,
|
||||
0x3b, 0x2c, 0x3b, 0x0c, 0x2b },
|
||||
{ STV0900_8PSK_56, 0x2e, 0x3e, 0x1e, 0x2e, 0x2d,
|
||||
0x1e, 0x3c, 0x2d, 0x2c, 0x1d },
|
||||
{ STV0900_8PSK_89, 0x3e, 0x3e, 0x1e, 0x2e, 0x3d,
|
||||
0x1e, 0x0d, 0x2d, 0x3c, 0x1d },
|
||||
{ STV0900_8PSK_910, 0x3e, 0x3e, 0x1e, 0x2e, 0x3d,
|
||||
0x1e, 0x1d, 0x2d, 0x0d, 0x1d },
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* Cut 2.0 Tracking carrier loop carrier 16APSK 2/3 to 32APSK 9/10 long Frame */
|
||||
static const struct stv0900_car_loop_optim FE_STV0900_S2APSKCarLoopCut20[11] = {
|
||||
/* Modcod 2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */
|
||||
{ STV0900_16APSK_23, 0x0C, 0x0C, 0x0C, 0x0C, 0x1D, 0x0C, 0x3C, 0x0C, 0x2C, 0x0C },
|
||||
{ STV0900_16APSK_34, 0x0C, 0x0C, 0x0C, 0x0C, 0x0E, 0x0C, 0x2D, 0x0C, 0x1D, 0x0C },
|
||||
{ STV0900_16APSK_45, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x0C, 0x3D, 0x0C, 0x2D, 0x0C },
|
||||
{ STV0900_16APSK_56, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x0C, 0x3D, 0x0C, 0x2D, 0x0C },
|
||||
{ STV0900_16APSK_89, 0x0C, 0x0C, 0x0C, 0x0C, 0x2E, 0x0C, 0x0E, 0x0C, 0x3D, 0x0C },
|
||||
{ STV0900_16APSK_910, 0x0C, 0x0C, 0x0C, 0x0C, 0x2E, 0x0C, 0x0E, 0x0C, 0x3D, 0x0C },
|
||||
{ STV0900_32APSK_34, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C },
|
||||
{ STV0900_32APSK_45, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C },
|
||||
{ STV0900_32APSK_56, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C },
|
||||
{ STV0900_32APSK_89, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C },
|
||||
{ STV0900_32APSK_910, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C }
|
||||
/* Modcod 2MPon 2MPoff 5MPon 5MPoff 10MPon
|
||||
10MPoff 20MPon 20MPoff 30MPon 30MPoff */
|
||||
{ STV0900_16APSK_23, 0x0C, 0x0C, 0x0C, 0x0C, 0x1D,
|
||||
0x0C, 0x3C, 0x0C, 0x2C, 0x0C },
|
||||
{ STV0900_16APSK_34, 0x0C, 0x0C, 0x0C, 0x0C, 0x0E,
|
||||
0x0C, 0x2D, 0x0C, 0x1D, 0x0C },
|
||||
{ STV0900_16APSK_45, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E,
|
||||
0x0C, 0x3D, 0x0C, 0x2D, 0x0C },
|
||||
{ STV0900_16APSK_56, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E,
|
||||
0x0C, 0x3D, 0x0C, 0x2D, 0x0C },
|
||||
{ STV0900_16APSK_89, 0x0C, 0x0C, 0x0C, 0x0C, 0x2E,
|
||||
0x0C, 0x0E, 0x0C, 0x3D, 0x0C },
|
||||
{ STV0900_16APSK_910, 0x0C, 0x0C, 0x0C, 0x0C, 0x2E,
|
||||
0x0C, 0x0E, 0x0C, 0x3D, 0x0C },
|
||||
{ STV0900_32APSK_34, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
|
||||
0x0C, 0x0C, 0x0C, 0x0C, 0x0C },
|
||||
{ STV0900_32APSK_45, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
|
||||
0x0C, 0x0C, 0x0C, 0x0C, 0x0C },
|
||||
{ STV0900_32APSK_56, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
|
||||
0x0C, 0x0C, 0x0C, 0x0C, 0x0C },
|
||||
{ STV0900_32APSK_89, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
|
||||
0x0C, 0x0C, 0x0C, 0x0C, 0x0C },
|
||||
{ STV0900_32APSK_910, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
|
||||
0x0C, 0x0C, 0x0C, 0x0C, 0x0C },
|
||||
};
|
||||
|
||||
|
||||
/* Cut 2.0 Tracking carrier loop carrier QPSK 1/4 to QPSK 2/5 long Frame */
|
||||
static const struct stv0900_car_loop_optim FE_STV0900_S2LowQPCarLoopCut20[3] = {
|
||||
/* Modcod 2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */
|
||||
{ STV0900_QPSK_14, 0x0F, 0x3F, 0x0E, 0x3F, 0x2D, 0x2F, 0x2D, 0x1F, 0x3D, 0x3E },
|
||||
{ STV0900_QPSK_13, 0x0F, 0x3F, 0x0E, 0x3F, 0x2D, 0x2F, 0x3D, 0x0F, 0x3D, 0x2E },
|
||||
{ STV0900_QPSK_25, 0x1F, 0x3F, 0x1E, 0x3F, 0x3D, 0x1F, 0x3D, 0x3E, 0x3D, 0x2E }
|
||||
/* Modcod 2MPon 2MPoff 5MPon 5MPoff 10MPon
|
||||
10MPoff 20MPon 20MPoff 30MPon 30MPoff */
|
||||
{ STV0900_QPSK_14, 0x0F, 0x3F, 0x0E, 0x3F, 0x2D,
|
||||
0x2F, 0x2D, 0x1F, 0x3D, 0x3E },
|
||||
{ STV0900_QPSK_13, 0x0F, 0x3F, 0x0E, 0x3F, 0x2D,
|
||||
0x2F, 0x3D, 0x0F, 0x3D, 0x2E },
|
||||
{ STV0900_QPSK_25, 0x1F, 0x3F, 0x1E, 0x3F, 0x3D,
|
||||
0x1F, 0x3D, 0x3E, 0x3D, 0x2E }
|
||||
};
|
||||
|
||||
|
||||
/* Cut 2.0 Tracking carrier loop carrier short Frame, cut 1.2 and 2.0 */
|
||||
static const struct stv0900_short_frames_car_loop_optim FE_STV0900_S2ShortCarLoop[4] = {
|
||||
/*Mod 2M_cut1.2 2M_cut2.0 5M_cut1.2 5M_cut2.0 10M_cut1.2 10M_cut2.0 20M_cut1.2 20M_cut2.0 30M_cut1.2 30M_cut2.0 */
|
||||
{ STV0900_QPSK, 0x3C, 0x2F, 0x2B, 0x2E, 0x0B, 0x0E, 0x3A, 0x0E, 0x2A, 0x3D },
|
||||
{ STV0900_8PSK, 0x0B, 0x3E, 0x2A, 0x0E, 0x0A, 0x2D, 0x19, 0x0D, 0x09, 0x3C },
|
||||
{ STV0900_16APSK, 0x1B, 0x1E, 0x1B, 0x1E, 0x1B, 0x1E, 0x3A, 0x3D, 0x2A, 0x2D },
|
||||
{ STV0900_32APSK, 0x1B, 0x1E, 0x1B, 0x1E, 0x1B, 0x1E, 0x3A, 0x3D, 0x2A, 0x2D }
|
||||
static const
|
||||
struct stv0900_short_frames_car_loop_optim FE_STV0900_S2ShortCarLoop[4] = {
|
||||
/*Mod 2Mcut1.2 2Mcut2.0 5Mcut1.2 5Mcut2.0 10Mcut1.2
|
||||
10Mcut2.0 20Mcut1.2 20M_cut2.0 30Mcut1.2 30Mcut2.0*/
|
||||
{ STV0900_QPSK, 0x3C, 0x2F, 0x2B, 0x2E, 0x0B,
|
||||
0x0E, 0x3A, 0x0E, 0x2A, 0x3D },
|
||||
{ STV0900_8PSK, 0x0B, 0x3E, 0x2A, 0x0E, 0x0A,
|
||||
0x2D, 0x19, 0x0D, 0x09, 0x3C },
|
||||
{ STV0900_16APSK, 0x1B, 0x1E, 0x1B, 0x1E, 0x1B,
|
||||
0x1E, 0x3A, 0x3D, 0x2A, 0x2D },
|
||||
{ STV0900_32APSK, 0x1B, 0x1E, 0x1B, 0x1E, 0x1B,
|
||||
0x1E, 0x3A, 0x3D, 0x2A, 0x2D }
|
||||
};
|
||||
|
||||
static const u16 STV0900_InitVal[182][2] = {
|
||||
static const struct stv0900_car_loop_optim FE_STV0900_S2CarLoopCut30[14] = {
|
||||
/*Modcod 2MPon 2MPoff 5MPon 5MPoff 10MPon
|
||||
10MPoff 20MPon 20MPoff 30MPon 30MPoff */
|
||||
{ STV0900_QPSK_12, 0x3C, 0x2C, 0x0C, 0x2C, 0x1B,
|
||||
0x2C, 0x1B, 0x1C, 0x0B, 0x3B },
|
||||
{ STV0900_QPSK_35, 0x0D, 0x0D, 0x0C, 0x0D, 0x1B,
|
||||
0x3C, 0x1B, 0x1C, 0x0B, 0x3B },
|
||||
{ STV0900_QPSK_23, 0x1D, 0x0D, 0x0C, 0x1D, 0x2B,
|
||||
0x3C, 0x1B, 0x1C, 0x0B, 0x3B },
|
||||
{ STV0900_QPSK_34, 0x1D, 0x1D, 0x0C, 0x1D, 0x2B,
|
||||
0x3C, 0x1B, 0x1C, 0x0B, 0x3B },
|
||||
{ STV0900_QPSK_45, 0x2D, 0x1D, 0x1C, 0x1D, 0x2B,
|
||||
0x3C, 0x2B, 0x0C, 0x1B, 0x3B },
|
||||
{ STV0900_QPSK_56, 0x2D, 0x1D, 0x1C, 0x1D, 0x2B,
|
||||
0x3C, 0x2B, 0x0C, 0x1B, 0x3B },
|
||||
{ STV0900_QPSK_89, 0x3D, 0x2D, 0x1C, 0x1D, 0x3B,
|
||||
0x3C, 0x2B, 0x0C, 0x1B, 0x3B },
|
||||
{ STV0900_QPSK_910, 0x3D, 0x2D, 0x1C, 0x1D, 0x3B,
|
||||
0x3C, 0x2B, 0x0C, 0x1B, 0x3B },
|
||||
{ STV0900_8PSK_35, 0x39, 0x19, 0x39, 0x19, 0x19,
|
||||
0x19, 0x19, 0x19, 0x09, 0x19 },
|
||||
{ STV0900_8PSK_23, 0x2A, 0x39, 0x1A, 0x0A, 0x39,
|
||||
0x0A, 0x29, 0x39, 0x29, 0x0A },
|
||||
{ STV0900_8PSK_34, 0x0B, 0x3A, 0x0B, 0x0B, 0x3A,
|
||||
0x1B, 0x1A, 0x0B, 0x1A, 0x3A },
|
||||
{ STV0900_8PSK_56, 0x0C, 0x1B, 0x3B, 0x2B, 0x1B,
|
||||
0x3B, 0x3A, 0x3B, 0x3A, 0x1B },
|
||||
{ STV0900_8PSK_89, 0x2C, 0x2C, 0x2C, 0x1C, 0x2B,
|
||||
0x0C, 0x0B, 0x3B, 0x0B, 0x1B },
|
||||
{ STV0900_8PSK_910, 0x2C, 0x3C, 0x2C, 0x1C, 0x3B,
|
||||
0x1C, 0x0B, 0x3B, 0x0B, 0x1B }
|
||||
};
|
||||
|
||||
static const
|
||||
struct stv0900_car_loop_optim FE_STV0900_S2APSKCarLoopCut30[11] = {
|
||||
/*Modcod 2MPon 2MPoff 5MPon 5MPoff 10MPon
|
||||
10MPoff 20MPon 20MPoff 30MPon 30MPoff */
|
||||
{ STV0900_16APSK_23, 0x0A, 0x0A, 0x0A, 0x0A, 0x1A,
|
||||
0x0A, 0x3A, 0x0A, 0x2A, 0x0A },
|
||||
{ STV0900_16APSK_34, 0x0A, 0x0A, 0x0A, 0x0A, 0x0B,
|
||||
0x0A, 0x3B, 0x0A, 0x1B, 0x0A },
|
||||
{ STV0900_16APSK_45, 0x0A, 0x0A, 0x0A, 0x0A, 0x1B,
|
||||
0x0A, 0x3B, 0x0A, 0x2B, 0x0A },
|
||||
{ STV0900_16APSK_56, 0x0A, 0x0A, 0x0A, 0x0A, 0x1B,
|
||||
0x0A, 0x3B, 0x0A, 0x2B, 0x0A },
|
||||
{ STV0900_16APSK_89, 0x0A, 0x0A, 0x0A, 0x0A, 0x2B,
|
||||
0x0A, 0x0C, 0x0A, 0x3B, 0x0A },
|
||||
{ STV0900_16APSK_910, 0x0A, 0x0A, 0x0A, 0x0A, 0x2B,
|
||||
0x0A, 0x0C, 0x0A, 0x3B, 0x0A },
|
||||
{ STV0900_32APSK_34, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
|
||||
0x0A, 0x0A, 0x0A, 0x0A, 0x0A },
|
||||
{ STV0900_32APSK_45, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
|
||||
0x0A, 0x0A, 0x0A, 0x0A, 0x0A },
|
||||
{ STV0900_32APSK_56, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
|
||||
0x0A, 0x0A, 0x0A, 0x0A, 0x0A },
|
||||
{ STV0900_32APSK_89, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
|
||||
0x0A, 0x0A, 0x0A, 0x0A, 0x0A },
|
||||
{ STV0900_32APSK_910, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
|
||||
0x0A, 0x0A, 0x0A, 0x0A, 0x0A }
|
||||
};
|
||||
|
||||
static const
|
||||
struct stv0900_car_loop_optim FE_STV0900_S2LowQPCarLoopCut30[3] = {
|
||||
/*Modcod 2MPon 2MPoff 5MPon 5MPoff 10MPon
|
||||
10MPoff 20MPon 20MPoff 30MPon 30MPoff*/
|
||||
{ STV0900_QPSK_14, 0x0C, 0x3C, 0x0B, 0x3C, 0x2A,
|
||||
0x2C, 0x2A, 0x1C, 0x3A, 0x3B },
|
||||
{ STV0900_QPSK_13, 0x0C, 0x3C, 0x0B, 0x3C, 0x2A,
|
||||
0x2C, 0x3A, 0x0C, 0x3A, 0x2B },
|
||||
{ STV0900_QPSK_25, 0x1C, 0x3C, 0x1B, 0x3C, 0x3A,
|
||||
0x1C, 0x3A, 0x3B, 0x3A, 0x2B }
|
||||
};
|
||||
|
||||
static const struct stv0900_short_frames_car_loop_optim_vs_mod
|
||||
FE_STV0900_S2ShortCarLoopCut30[4] = {
|
||||
/*Mod 2Mcut3.0 5Mcut3.0 10Mcut3.0 20Mcut3.0 30Mcut3.0*/
|
||||
{ STV0900_QPSK, 0x2C, 0x2B, 0x0B, 0x0B, 0x3A },
|
||||
{ STV0900_8PSK, 0x3B, 0x0B, 0x2A, 0x0A, 0x39 },
|
||||
{ STV0900_16APSK, 0x1B, 0x1B, 0x1B, 0x3A, 0x2A },
|
||||
{ STV0900_32APSK, 0x1B, 0x1B, 0x1B, 0x3A, 0x2A },
|
||||
|
||||
};
|
||||
|
||||
static const u16 STV0900_InitVal[181][2] = {
|
||||
{ R0900_OUTCFG , 0x00 },
|
||||
{ R0900_MODECFG , 0xff },
|
||||
{ R0900_AGCRF1CFG , 0x11 },
|
||||
{ R0900_AGCRF2CFG , 0x13 },
|
||||
{ R0900_TSGENERAL1X , 0x14 },
|
||||
|
|
@ -381,7 +524,7 @@ static const u16 STV0900_InitVal[182][2] = {
|
|||
{ R0900_GAINLLR_NF15 , 0x1A },
|
||||
{ R0900_GAINLLR_NF16 , 0x1F },
|
||||
{ R0900_GAINLLR_NF17 , 0x21 },
|
||||
{ R0900_RCCFGH , 0x20 },
|
||||
{ R0900_RCCFG2 , 0x20 },
|
||||
{ R0900_P1_FECM , 0x01 }, /*disable DSS modes*/
|
||||
{ R0900_P2_FECM , 0x01 }, /*disable DSS modes*/
|
||||
{ R0900_P1_PRVIT , 0x2F }, /*disable puncture rate 6/7*/
|
||||
|
|
|
|||
|
|
@ -46,22 +46,6 @@
|
|||
#define FALSE (!TRUE)
|
||||
#endif
|
||||
|
||||
#define dmd_reg(a, b, c) \
|
||||
do { \
|
||||
a = 0; \
|
||||
switch (demod) { \
|
||||
case STV0900_DEMOD_1: \
|
||||
default: \
|
||||
a = b; \
|
||||
break; \
|
||||
case STV0900_DEMOD_2: \
|
||||
a = c; \
|
||||
break; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static int stvdebug;
|
||||
|
||||
#define dprintk(args...) \
|
||||
do { \
|
||||
if (stvdebug) \
|
||||
|
|
@ -70,6 +54,8 @@ static int stvdebug;
|
|||
|
||||
#define STV0900_MAXLOOKUPSIZE 500
|
||||
#define STV0900_BLIND_SEARCH_AGC2_TH 700
|
||||
#define STV0900_BLIND_SEARCH_AGC2_TH_CUT30 1400
|
||||
#define IQPOWER_THRESHOLD 30
|
||||
|
||||
/* One point of the lookup table */
|
||||
struct stv000_lookpoint {
|
||||
|
|
@ -263,14 +249,14 @@ struct stv0900_init_params{
|
|||
int tuner1_adc;
|
||||
|
||||
/* IQ from the tuner1 to the demod */
|
||||
enum stv0900_iq_inversion tun1_iq_inversion;
|
||||
enum stv0900_iq_inversion tun1_iq_inv;
|
||||
enum fe_stv0900_clock_type path2_ts_clock;
|
||||
|
||||
u8 tun2_maddress;
|
||||
int tuner2_adc;
|
||||
|
||||
/* IQ from the tuner2 to the demod */
|
||||
enum stv0900_iq_inversion tun2_iq_inversion;
|
||||
enum stv0900_iq_inversion tun2_iq_inv;
|
||||
struct stv0900_reg *ts_config;
|
||||
};
|
||||
|
||||
|
|
@ -300,7 +286,7 @@ struct stv0900_signal_info {
|
|||
enum fe_stv0900_modcode modcode;
|
||||
enum fe_stv0900_modulation modulation;
|
||||
enum fe_stv0900_pilot pilot;
|
||||
enum fe_stv0900_frame_length frame_length;
|
||||
enum fe_stv0900_frame_length frame_len;
|
||||
enum stv0900_iq_inversion spectrum;
|
||||
enum fe_stv0900_rolloff rolloff;
|
||||
|
||||
|
|
@ -318,47 +304,25 @@ struct stv0900_internal{
|
|||
/* Demodulator use for single demod or for dual demod) */
|
||||
enum fe_stv0900_demod_mode demod_mode;
|
||||
|
||||
/*Demod 1*/
|
||||
s32 tuner1_freq;
|
||||
s32 tuner1_bw;
|
||||
s32 dmd1_symbol_rate;
|
||||
s32 dmd1_srch_range;
|
||||
/*Demods */
|
||||
s32 freq[2];
|
||||
s32 bw[2];
|
||||
s32 symbol_rate[2];
|
||||
s32 srch_range[2];
|
||||
|
||||
/* algorithm for search Blind, Cold or Warm*/
|
||||
enum fe_stv0900_search_algo dmd1_srch_algo;
|
||||
enum fe_stv0900_search_algo srch_algo[2];
|
||||
/* search standard: Auto, DVBS1/DSS only or DVBS2 only*/
|
||||
enum fe_stv0900_search_standard dmd1_srch_standard;
|
||||
enum fe_stv0900_search_standard srch_standard[2];
|
||||
/* inversion search : auto, auto norma first, normal or inverted */
|
||||
enum fe_stv0900_search_iq dmd1_srch_iq_inv;
|
||||
enum fe_stv0900_modcode dmd1_modcode;
|
||||
enum fe_stv0900_modulation dmd1_modulation;
|
||||
enum fe_stv0900_fec dmd1_fec;
|
||||
enum fe_stv0900_search_iq srch_iq_inv[2];
|
||||
enum fe_stv0900_modcode modcode[2];
|
||||
enum fe_stv0900_modulation modulation[2];
|
||||
enum fe_stv0900_fec fec[2];
|
||||
|
||||
struct stv0900_signal_info dmd1_rslts;
|
||||
enum fe_stv0900_signal_type dmd1_state;
|
||||
struct stv0900_signal_info result[2];
|
||||
enum fe_stv0900_error err[2];
|
||||
|
||||
enum fe_stv0900_error dmd1_err;
|
||||
|
||||
/*Demod 2*/
|
||||
s32 tuner2_freq;
|
||||
s32 tuner2_bw;
|
||||
s32 dmd2_symbol_rate;
|
||||
s32 dmd2_srch_range;
|
||||
|
||||
enum fe_stv0900_search_algo dmd2_srch_algo;
|
||||
enum fe_stv0900_search_standard dmd2_srch_stndrd;
|
||||
/* inversion search : auto, auto normal first, normal or inverted */
|
||||
enum fe_stv0900_search_iq dmd2_srch_iq_inv;
|
||||
enum fe_stv0900_modcode dmd2_modcode;
|
||||
enum fe_stv0900_modulation dmd2_modulation;
|
||||
enum fe_stv0900_fec dmd2_fec;
|
||||
|
||||
/* results of the search*/
|
||||
struct stv0900_signal_info dmd2_rslts;
|
||||
/* current state of the search algorithm */
|
||||
enum fe_stv0900_signal_type dmd2_state;
|
||||
|
||||
enum fe_stv0900_error dmd2_err;
|
||||
|
||||
struct i2c_adapter *i2c_adap;
|
||||
u8 i2c_addr;
|
||||
|
|
@ -379,6 +343,8 @@ struct stv0900_state {
|
|||
int demod;
|
||||
};
|
||||
|
||||
extern int stvdebug;
|
||||
|
||||
extern s32 ge2comp(s32 a, s32 width);
|
||||
|
||||
extern void stv0900_write_reg(struct stv0900_internal *i_params,
|
||||
|
|
@ -418,13 +384,14 @@ extern u8 stv0900_get_optim_short_carr_loop(s32 srate,
|
|||
extern void stv0900_stop_all_s2_modcod(struct stv0900_internal *i_params,
|
||||
enum fe_stv0900_demod_num demod);
|
||||
|
||||
extern void stv0900_activate_s2_modcode(struct stv0900_internal *i_params,
|
||||
extern void stv0900_activate_s2_modcod(struct stv0900_internal *i_params,
|
||||
enum fe_stv0900_demod_num demod);
|
||||
|
||||
extern void stv0900_activate_s2_modcode_single(struct stv0900_internal *i_params,
|
||||
extern void stv0900_activate_s2_modcod_single(struct stv0900_internal *i_params,
|
||||
enum fe_stv0900_demod_num demod);
|
||||
|
||||
extern enum fe_stv0900_tracking_standard stv0900_get_standard(struct dvb_frontend *fe,
|
||||
extern enum
|
||||
fe_stv0900_tracking_standard stv0900_get_standard(struct dvb_frontend *fe,
|
||||
enum fe_stv0900_demod_num demod);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -825,7 +825,7 @@ static int stv090x_set_min_srate(struct stv090x_state *state, u32 clk, u32 srate
|
|||
sym /= (state->mclk >> 7);
|
||||
}
|
||||
|
||||
if (STV090x_WRITE_DEMOD(state, SFRLOW1, ((sym >> 8) & 0xff)) < 0) /* MSB */
|
||||
if (STV090x_WRITE_DEMOD(state, SFRLOW1, ((sym >> 8) & 0x7f)) < 0) /* MSB */
|
||||
goto err;
|
||||
if (STV090x_WRITE_DEMOD(state, SFRLOW0, (sym & 0xff)) < 0) /* LSB */
|
||||
goto err;
|
||||
|
|
@ -1238,6 +1238,8 @@ static int stv090x_delivery_search(struct stv090x_state *state)
|
|||
goto err;
|
||||
}
|
||||
|
||||
if (stv090x_set_vit_thtracq(state) < 0)
|
||||
goto err;
|
||||
break;
|
||||
|
||||
case STV090x_SEARCH_AUTO:
|
||||
|
|
@ -1278,17 +1280,8 @@ static int stv090x_delivery_search(struct stv090x_state *state)
|
|||
goto err;
|
||||
}
|
||||
|
||||
if (state->srate >= 2000000) {
|
||||
/* Srate >= 2MSPS, Viterbi threshold to acquire */
|
||||
if (stv090x_set_vit_thacq(state) < 0)
|
||||
goto err;
|
||||
} else {
|
||||
/* Srate < 2MSPS, Reset Viterbi thresholdto track
|
||||
* and then re-acquire
|
||||
*/
|
||||
if (stv090x_set_vit_thtracq(state) < 0)
|
||||
goto err;
|
||||
}
|
||||
if (stv090x_set_vit_thacq(state) < 0)
|
||||
goto err;
|
||||
|
||||
if (stv090x_set_viterbi(state) < 0)
|
||||
goto err;
|
||||
|
|
@ -1317,7 +1310,7 @@ static int stv090x_start_search(struct stv090x_state *state)
|
|||
goto err;
|
||||
if (STV090x_WRITE_DEMOD(state, CFRUP1, 0x0f) < 0)
|
||||
goto err;
|
||||
if (STV090x_WRITE_DEMOD(state, CFRUP1, 0xff) < 0)
|
||||
if (STV090x_WRITE_DEMOD(state, CFRUP0, 0xff) < 0)
|
||||
goto err;
|
||||
if (STV090x_WRITE_DEMOD(state, CFRLOW1, 0xf0) < 0)
|
||||
goto err;
|
||||
|
|
@ -1371,7 +1364,7 @@ static int stv090x_start_search(struct stv090x_state *state)
|
|||
|
||||
if (STV090x_WRITE_DEMOD(state, CFRUP1, MSB(freq)) < 0)
|
||||
goto err;
|
||||
if (STV090x_WRITE_DEMOD(state, CFRUP1, LSB(freq)) < 0)
|
||||
if (STV090x_WRITE_DEMOD(state, CFRUP0, LSB(freq)) < 0)
|
||||
goto err;
|
||||
|
||||
freq *= -1;
|
||||
|
|
@ -1422,6 +1415,9 @@ static int stv090x_start_search(struct stv090x_state *state)
|
|||
if (STV090x_WRITE_DEMOD(state, DMDCFG2, reg) < 0)
|
||||
goto err;
|
||||
|
||||
if (STV090x_WRITE_DEMOD(state, RTC, 0x88) < 0)
|
||||
goto err;
|
||||
|
||||
if (state->dev_ver >= 0x20) {
|
||||
/*Frequency offset detector setting*/
|
||||
if (state->srate < 2000000) {
|
||||
|
|
@ -1430,20 +1426,22 @@ static int stv090x_start_search(struct stv090x_state *state)
|
|||
if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x39) < 0)
|
||||
goto err;
|
||||
} else {
|
||||
/* Cut 2 */
|
||||
/* Cut 3 */
|
||||
if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x89) < 0)
|
||||
goto err;
|
||||
}
|
||||
if (STV090x_WRITE_DEMOD(state, CARHDR, 0x40) < 0)
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (state->srate < 10000000) {
|
||||
} else if (state->srate < 10000000) {
|
||||
if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x4c) < 0)
|
||||
goto err;
|
||||
if (STV090x_WRITE_DEMOD(state, CARHDR, 0x20) < 0)
|
||||
goto err;
|
||||
} else {
|
||||
if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x4b) < 0)
|
||||
goto err;
|
||||
if (STV090x_WRITE_DEMOD(state, CARHDR, 0x20) < 0)
|
||||
goto err;
|
||||
}
|
||||
} else {
|
||||
if (state->srate < 10000000) {
|
||||
|
|
@ -1485,14 +1483,14 @@ err:
|
|||
|
||||
static int stv090x_get_agc2_min_level(struct stv090x_state *state)
|
||||
{
|
||||
u32 agc2_min = 0, agc2 = 0, freq_init, freq_step, reg;
|
||||
u32 agc2_min = 0xffff, agc2 = 0, freq_init, freq_step, reg;
|
||||
s32 i, j, steps, dir;
|
||||
|
||||
if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x38) < 0)
|
||||
goto err;
|
||||
reg = STV090x_READ_DEMOD(state, DMDCFGMD);
|
||||
STV090x_SETFIELD_Px(reg, SCAN_ENABLE_FIELD, 1);
|
||||
STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 1);
|
||||
STV090x_SETFIELD_Px(reg, SCAN_ENABLE_FIELD, 0);
|
||||
STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 0);
|
||||
if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
|
||||
goto err;
|
||||
|
||||
|
|
@ -1509,10 +1507,8 @@ static int stv090x_get_agc2_min_level(struct stv090x_state *state)
|
|||
if (stv090x_set_srate(state, 1000000) < 0)
|
||||
goto err;
|
||||
|
||||
steps = -1 + state->search_range / 1000000;
|
||||
steps /= 2;
|
||||
steps = (2 * steps) + 1;
|
||||
if (steps < 0)
|
||||
steps = state->search_range / 1000000;
|
||||
if (steps <= 0)
|
||||
steps = 1;
|
||||
|
||||
dir = 1;
|
||||
|
|
@ -1525,7 +1521,7 @@ static int stv090x_get_agc2_min_level(struct stv090x_state *state)
|
|||
else
|
||||
freq_init = freq_init - (freq_step * i);
|
||||
|
||||
dir = -1;
|
||||
dir *= -1;
|
||||
|
||||
if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x5c) < 0) /* Demod RESET */
|
||||
goto err;
|
||||
|
|
@ -1536,13 +1532,14 @@ static int stv090x_get_agc2_min_level(struct stv090x_state *state)
|
|||
if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x58) < 0) /* Demod RESET */
|
||||
goto err;
|
||||
msleep(10);
|
||||
|
||||
agc2 = 0;
|
||||
for (j = 0; j < 10; j++) {
|
||||
agc2 += STV090x_READ_DEMOD(state, AGC2I1) << 8;
|
||||
agc2 |= STV090x_READ_DEMOD(state, AGC2I0);
|
||||
agc2 += (STV090x_READ_DEMOD(state, AGC2I1) << 8) |
|
||||
STV090x_READ_DEMOD(state, AGC2I0);
|
||||
}
|
||||
agc2 /= 10;
|
||||
agc2_min = 0xffff;
|
||||
if (agc2 < 0xffff)
|
||||
if (agc2 < agc2_min)
|
||||
agc2_min = agc2;
|
||||
}
|
||||
|
||||
|
|
@ -1584,6 +1581,12 @@ static u32 stv090x_srate_srch_coarse(struct stv090x_state *state)
|
|||
int tmg_lock = 0, i;
|
||||
s32 tmg_cpt = 0, dir = 1, steps, cur_step = 0, freq;
|
||||
u32 srate_coarse = 0, agc2 = 0, car_step = 1200, reg;
|
||||
u32 agc2th;
|
||||
|
||||
if (state->dev_ver >= 0x30)
|
||||
agc2th = 0x2e00;
|
||||
else
|
||||
agc2th = 0x1f00;
|
||||
|
||||
reg = STV090x_READ_DEMOD(state, DMDISTATE);
|
||||
STV090x_SETFIELD_Px(reg, I2C_DEMOD_MODE_FIELD, 0x1f); /* Demod RESET */
|
||||
|
|
@ -1591,13 +1594,15 @@ static u32 stv090x_srate_srch_coarse(struct stv090x_state *state)
|
|||
goto err;
|
||||
if (STV090x_WRITE_DEMOD(state, TMGCFG, 0x12) < 0)
|
||||
goto err;
|
||||
if (STV090x_WRITE_DEMOD(state, TMGCFG2, 0xc0) < 0)
|
||||
goto err;
|
||||
if (STV090x_WRITE_DEMOD(state, TMGTHRISE, 0xf0) < 0)
|
||||
goto err;
|
||||
if (STV090x_WRITE_DEMOD(state, TMGTHFALL, 0xe0) < 0)
|
||||
goto err;
|
||||
reg = STV090x_READ_DEMOD(state, DMDCFGMD);
|
||||
STV090x_SETFIELD_Px(reg, SCAN_ENABLE_FIELD, 1);
|
||||
STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 1);
|
||||
STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 0);
|
||||
if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
|
||||
goto err;
|
||||
|
||||
|
|
@ -1611,13 +1616,13 @@ static u32 stv090x_srate_srch_coarse(struct stv090x_state *state)
|
|||
goto err;
|
||||
if (STV090x_WRITE_DEMOD(state, DMDTOM, 0x00) < 0)
|
||||
goto err;
|
||||
if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x60) < 0)
|
||||
if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x50) < 0)
|
||||
goto err;
|
||||
|
||||
if (state->dev_ver >= 0x30) {
|
||||
if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x99) < 0)
|
||||
goto err;
|
||||
if (STV090x_WRITE_DEMOD(state, SFRSTEP, 0x95) < 0)
|
||||
if (STV090x_WRITE_DEMOD(state, SFRSTEP, 0x98) < 0)
|
||||
goto err;
|
||||
|
||||
} else if (state->dev_ver >= 0x20) {
|
||||
|
|
@ -1652,23 +1657,31 @@ static u32 stv090x_srate_srch_coarse(struct stv090x_state *state)
|
|||
while ((!tmg_lock) && (cur_step < steps)) {
|
||||
if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x5f) < 0) /* Demod RESET */
|
||||
goto err;
|
||||
reg = STV090x_READ_DEMOD(state, DMDISTATE);
|
||||
STV090x_SETFIELD_Px(reg, I2C_DEMOD_MODE_FIELD, 0x00); /* trigger acquisition */
|
||||
if (STV090x_WRITE_DEMOD(state, DMDISTATE, reg) < 0)
|
||||
if (STV090x_WRITE_DEMOD(state, CFRINIT1, 0x00) < 0)
|
||||
goto err;
|
||||
if (STV090x_WRITE_DEMOD(state, CFRINIT0, 0x00) < 0)
|
||||
goto err;
|
||||
if (STV090x_WRITE_DEMOD(state, SFRINIT1, 0x00) < 0)
|
||||
goto err;
|
||||
if (STV090x_WRITE_DEMOD(state, SFRINIT0, 0x00) < 0)
|
||||
goto err;
|
||||
/* trigger acquisition */
|
||||
if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x40) < 0)
|
||||
goto err;
|
||||
msleep(50);
|
||||
for (i = 0; i < 10; i++) {
|
||||
reg = STV090x_READ_DEMOD(state, DSTATUS);
|
||||
if (STV090x_GETFIELD_Px(reg, TMGLOCK_QUALITY_FIELD) >= 2)
|
||||
tmg_cpt++;
|
||||
agc2 += STV090x_READ_DEMOD(state, AGC2I1) << 8;
|
||||
agc2 |= STV090x_READ_DEMOD(state, AGC2I0);
|
||||
agc2 += (STV090x_READ_DEMOD(state, AGC2I1) << 8) |
|
||||
STV090x_READ_DEMOD(state, AGC2I0);
|
||||
}
|
||||
agc2 /= 10;
|
||||
srate_coarse = stv090x_get_srate(state, state->mclk);
|
||||
cur_step++;
|
||||
dir *= -1;
|
||||
if ((tmg_cpt >= 5) && (agc2 < 0x1f00) && (srate_coarse < 55000000) && (srate_coarse > 850000))
|
||||
if ((tmg_cpt >= 5) && (agc2 < agc2th) &&
|
||||
(srate_coarse < 50000000) && (srate_coarse > 850000))
|
||||
tmg_lock = 1;
|
||||
else if (cur_step < steps) {
|
||||
if (dir > 0)
|
||||
|
|
@ -1681,7 +1694,7 @@ static u32 stv090x_srate_srch_coarse(struct stv090x_state *state)
|
|||
goto err;
|
||||
|
||||
if (state->config->tuner_set_frequency) {
|
||||
if (state->config->tuner_set_frequency(fe, state->frequency) < 0)
|
||||
if (state->config->tuner_set_frequency(fe, freq) < 0)
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
|
@ -1738,7 +1751,7 @@ static u32 stv090x_srate_srch_fine(struct stv090x_state *state)
|
|||
else {
|
||||
if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0) /* Demod RESET */
|
||||
goto err;
|
||||
if (STV090x_WRITE_DEMOD(state, TMGCFG2, 0x01) < 0)
|
||||
if (STV090x_WRITE_DEMOD(state, TMGCFG2, 0xc1) < 0)
|
||||
goto err;
|
||||
if (STV090x_WRITE_DEMOD(state, TMGTHRISE, 0x20) < 0)
|
||||
goto err;
|
||||
|
|
@ -1751,6 +1764,9 @@ static u32 stv090x_srate_srch_fine(struct stv090x_state *state)
|
|||
if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
|
||||
goto err;
|
||||
|
||||
if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x38) < 0)
|
||||
goto err;
|
||||
|
||||
if (state->dev_ver >= 0x30) {
|
||||
if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x79) < 0)
|
||||
goto err;
|
||||
|
|
@ -1856,12 +1872,12 @@ static int stv090x_get_dmdlock(struct stv090x_state *state, s32 timeout)
|
|||
static int stv090x_blind_search(struct stv090x_state *state)
|
||||
{
|
||||
u32 agc2, reg, srate_coarse;
|
||||
s32 timeout_dmd = 500, cpt_fail, agc2_ovflw, i;
|
||||
s32 cpt_fail, agc2_ovflw, i;
|
||||
u8 k_ref, k_max, k_min;
|
||||
int coarse_fail, lock;
|
||||
|
||||
k_max = 120;
|
||||
k_min = 30;
|
||||
k_max = 110;
|
||||
k_min = 10;
|
||||
|
||||
agc2 = stv090x_get_agc2_min_level(state);
|
||||
|
||||
|
|
@ -1900,7 +1916,8 @@ static int stv090x_blind_search(struct stv090x_state *state)
|
|||
srate_coarse = stv090x_srate_srch_fine(state);
|
||||
if (srate_coarse != 0) {
|
||||
stv090x_get_lock_tmg(state);
|
||||
lock = stv090x_get_dmdlock(state, timeout_dmd);
|
||||
lock = stv090x_get_dmdlock(state,
|
||||
state->DemodTimeout);
|
||||
} else {
|
||||
lock = 0;
|
||||
}
|
||||
|
|
@ -1908,8 +1925,8 @@ static int stv090x_blind_search(struct stv090x_state *state)
|
|||
cpt_fail = 0;
|
||||
agc2_ovflw = 0;
|
||||
for (i = 0; i < 10; i++) {
|
||||
agc2 = STV090x_READ_DEMOD(state, AGC2I1) << 8;
|
||||
agc2 |= STV090x_READ_DEMOD(state, AGC2I0);
|
||||
agc2 += (STV090x_READ_DEMOD(state, AGC2I1) << 8) |
|
||||
STV090x_READ_DEMOD(state, AGC2I0);
|
||||
if (agc2 >= 0xff00)
|
||||
agc2_ovflw++;
|
||||
reg = STV090x_READ_DEMOD(state, DSTATUS2);
|
||||
|
|
@ -1923,7 +1940,7 @@ static int stv090x_blind_search(struct stv090x_state *state)
|
|||
|
||||
lock = 0;
|
||||
}
|
||||
k_ref -= 30;
|
||||
k_ref -= 20;
|
||||
} while ((k_ref >= k_min) && (!lock) && (!coarse_fail));
|
||||
}
|
||||
|
||||
|
|
@ -2062,7 +2079,7 @@ static int stv090x_get_coldlock(struct stv090x_state *state, s32 timeout_dmd)
|
|||
goto err;
|
||||
|
||||
if (state->config->tuner_set_frequency) {
|
||||
if (state->config->tuner_set_frequency(fe, state->frequency) < 0)
|
||||
if (state->config->tuner_set_frequency(fe, freq) < 0)
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
|
@ -2093,17 +2110,6 @@ static int stv090x_get_coldlock(struct stv090x_state *state, s32 timeout_dmd)
|
|||
goto err;
|
||||
|
||||
STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1c);
|
||||
if (state->delsys == STV090x_DVBS2) {
|
||||
reg = STV090x_READ_DEMOD(state, DMDCFGMD);
|
||||
STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 0);
|
||||
STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 0);
|
||||
if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
|
||||
goto err;
|
||||
STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 1);
|
||||
STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 1);
|
||||
if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
|
||||
goto err;
|
||||
}
|
||||
if (STV090x_WRITE_DEMOD(state, CFRINIT1, 0x00) < 0)
|
||||
goto err;
|
||||
if (STV090x_WRITE_DEMOD(state, CFRINIT0, 0x00) < 0)
|
||||
|
|
@ -2425,7 +2431,7 @@ static s32 stv090x_get_car_freq(struct stv090x_state *state, u32 mclk)
|
|||
|
||||
derot = (int_1 * int_2) +
|
||||
((int_1 * tmp_2) >> 12) +
|
||||
((int_1 * tmp_1) >> 12);
|
||||
((int_2 * tmp_1) >> 12);
|
||||
|
||||
return derot;
|
||||
}
|
||||
|
|
@ -2732,7 +2738,7 @@ static int stv090x_optimize_track(struct stv090x_state *state)
|
|||
switch (state->delsys) {
|
||||
case STV090x_DVBS1:
|
||||
case STV090x_DSS:
|
||||
if (state->algo == STV090x_SEARCH_AUTO) {
|
||||
if (state->search_mode == STV090x_SEARCH_AUTO) {
|
||||
reg = STV090x_READ_DEMOD(state, DMDCFGMD);
|
||||
STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 1);
|
||||
STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 0);
|
||||
|
|
@ -2857,6 +2863,9 @@ static int stv090x_optimize_track(struct stv090x_state *state)
|
|||
if (stv090x_set_srate(state, srate) < 0)
|
||||
goto err;
|
||||
blind_tune = 1;
|
||||
|
||||
if (stv090x_dvbs_track_crl(state) < 0)
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (state->dev_ver >= 0x20) {
|
||||
|
|
@ -3042,7 +3051,7 @@ static enum stv090x_signal_state stv090x_algo(struct stv090x_state *state)
|
|||
struct dvb_frontend *fe = &state->frontend;
|
||||
enum stv090x_signal_state signal_state = STV090x_NOCARRIER;
|
||||
u32 reg;
|
||||
s32 timeout_dmd = 500, timeout_fec = 50, agc1_power, power_iq = 0, i;
|
||||
s32 agc1_power, power_iq = 0, i;
|
||||
int lock = 0, low_sr = 0, no_signal = 0;
|
||||
|
||||
reg = STV090x_READ_DEMOD(state, TSCFGH);
|
||||
|
|
@ -3054,8 +3063,13 @@ static enum stv090x_signal_state stv090x_algo(struct stv090x_state *state)
|
|||
goto err;
|
||||
|
||||
if (state->dev_ver >= 0x20) {
|
||||
if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x9e) < 0) /* cut 2.0 */
|
||||
goto err;
|
||||
if (state->srate > 5000000) {
|
||||
if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x9e) < 0)
|
||||
goto err;
|
||||
} else {
|
||||
if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x82) < 0)
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
stv090x_get_lock_tmg(state);
|
||||
|
|
@ -3175,7 +3189,7 @@ static enum stv090x_signal_state stv090x_algo(struct stv090x_state *state)
|
|||
if ((agc1_power == 0) && (power_iq < STV090x_IQPOWER_THRESHOLD)) {
|
||||
dprintk(FE_ERROR, 1, "No Signal: POWER_IQ=0x%02x", power_iq);
|
||||
lock = 0;
|
||||
|
||||
signal_state = STV090x_NOAGC1;
|
||||
} else {
|
||||
reg = STV090x_READ_DEMOD(state, DEMOD);
|
||||
STV090x_SETFIELD_Px(reg, SPECINV_CONTROL_FIELD, state->inversion);
|
||||
|
|
@ -3199,18 +3213,17 @@ static enum stv090x_signal_state stv090x_algo(struct stv090x_state *state)
|
|||
}
|
||||
}
|
||||
|
||||
/* need to check for AGC1 state */
|
||||
|
||||
|
||||
if (signal_state == STV090x_NOAGC1)
|
||||
return signal_state;
|
||||
|
||||
if (state->algo == STV090x_BLIND_SEARCH)
|
||||
lock = stv090x_blind_search(state);
|
||||
|
||||
else if (state->algo == STV090x_COLD_SEARCH)
|
||||
lock = stv090x_get_coldlock(state, timeout_dmd);
|
||||
lock = stv090x_get_coldlock(state, state->DemodTimeout);
|
||||
|
||||
else if (state->algo == STV090x_WARM_SEARCH)
|
||||
lock = stv090x_get_dmdlock(state, timeout_dmd);
|
||||
lock = stv090x_get_dmdlock(state, state->DemodTimeout);
|
||||
|
||||
if ((!lock) && (state->algo == STV090x_COLD_SEARCH)) {
|
||||
if (!low_sr) {
|
||||
|
|
@ -3245,8 +3258,9 @@ static enum stv090x_signal_state stv090x_algo(struct stv090x_state *state)
|
|||
goto err;
|
||||
}
|
||||
|
||||
if (stv090x_get_lock(state, timeout_fec, timeout_fec)) {
|
||||
lock = 1;
|
||||
lock = stv090x_get_lock(state, state->FecTimeout,
|
||||
state->FecTimeout);
|
||||
if (lock) {
|
||||
if (state->delsys == STV090x_DVBS2) {
|
||||
stv090x_set_s2rolloff(state);
|
||||
|
||||
|
|
@ -3273,7 +3287,6 @@ static enum stv090x_signal_state stv090x_algo(struct stv090x_state *state)
|
|||
if (STV090x_WRITE_DEMOD(state, ERRCTRL2, 0xc1) < 0)
|
||||
goto err;
|
||||
} else {
|
||||
lock = 0;
|
||||
signal_state = STV090x_NODATA;
|
||||
no_signal = stv090x_chk_signal(state);
|
||||
}
|
||||
|
|
@ -3296,7 +3309,13 @@ static enum dvbfe_search stv090x_search(struct dvb_frontend *fe, struct dvb_fron
|
|||
state->search_mode = STV090x_SEARCH_AUTO;
|
||||
state->algo = STV090x_COLD_SEARCH;
|
||||
state->fec = STV090x_PRERR;
|
||||
state->search_range = 2000000;
|
||||
if (state->srate > 10000000) {
|
||||
dprintk(FE_DEBUG, 1, "Search range: 10 MHz");
|
||||
state->search_range = 10000000;
|
||||
} else {
|
||||
dprintk(FE_DEBUG, 1, "Search range: 5 MHz");
|
||||
state->search_range = 5000000;
|
||||
}
|
||||
|
||||
if (stv090x_algo(state) == STV090x_RANGEOK) {
|
||||
dprintk(FE_DEBUG, 1, "Search success!");
|
||||
|
|
@ -3309,7 +3328,6 @@ static enum dvbfe_search stv090x_search(struct dvb_frontend *fe, struct dvb_fron
|
|||
return DVBFE_ALGO_SEARCH_ERROR;
|
||||
}
|
||||
|
||||
/* FIXME! */
|
||||
static int stv090x_read_status(struct dvb_frontend *fe, enum fe_status *status)
|
||||
{
|
||||
struct stv090x_state *state = fe->demodulator_priv;
|
||||
|
|
@ -3331,9 +3349,15 @@ static int stv090x_read_status(struct dvb_frontend *fe, enum fe_status *status)
|
|||
dprintk(FE_DEBUG, 1, "Delivery system: DVB-S2");
|
||||
reg = STV090x_READ_DEMOD(state, DSTATUS);
|
||||
if (STV090x_GETFIELD_Px(reg, LOCK_DEFINITIF_FIELD)) {
|
||||
reg = STV090x_READ_DEMOD(state, TSSTATUS);
|
||||
if (STV090x_GETFIELD_Px(reg, TSFIFO_LINEOK_FIELD)) {
|
||||
*status = FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
|
||||
reg = STV090x_READ_DEMOD(state, PDELSTATUS1);
|
||||
if (STV090x_GETFIELD_Px(reg, PKTDELIN_LOCK_FIELD)) {
|
||||
reg = STV090x_READ_DEMOD(state, TSSTATUS);
|
||||
if (STV090x_GETFIELD_Px(reg, TSFIFO_LINEOK_FIELD)) {
|
||||
*status = FE_HAS_CARRIER |
|
||||
FE_HAS_VITERBI |
|
||||
FE_HAS_SYNC |
|
||||
FE_HAS_LOCK;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
@ -3412,14 +3436,12 @@ static int stv090x_table_lookup(const struct stv090x_tab *tab, int max, int val)
|
|||
int res = 0;
|
||||
int min = 0, med;
|
||||
|
||||
if (val < tab[min].read)
|
||||
res = tab[min].real;
|
||||
else if (val >= tab[max].read)
|
||||
res = tab[max].real;
|
||||
else {
|
||||
if ((val >= tab[min].read && val < tab[max].read) ||
|
||||
(val >= tab[max].read && val < tab[min].read)) {
|
||||
while ((max - min) > 1) {
|
||||
med = (max + min) / 2;
|
||||
if (val >= tab[min].read && val < tab[med].read)
|
||||
if ((val >= tab[min].read && val < tab[med].read) ||
|
||||
(val >= tab[med].read && val < tab[min].read))
|
||||
max = med;
|
||||
else
|
||||
min = med;
|
||||
|
|
@ -3428,6 +3450,18 @@ static int stv090x_table_lookup(const struct stv090x_tab *tab, int max, int val)
|
|||
(tab[max].real - tab[min].real) /
|
||||
(tab[max].read - tab[min].read)) +
|
||||
tab[min].real;
|
||||
} else {
|
||||
if (tab[min].read < tab[max].read) {
|
||||
if (val < tab[min].read)
|
||||
res = tab[min].real;
|
||||
else if (val >= tab[max].read)
|
||||
res = tab[max].real;
|
||||
} else {
|
||||
if (val >= tab[min].read)
|
||||
res = tab[min].real;
|
||||
else if (val < tab[max].read)
|
||||
res = tab[max].real;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
|
|
@ -3437,16 +3471,22 @@ static int stv090x_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
|
|||
{
|
||||
struct stv090x_state *state = fe->demodulator_priv;
|
||||
u32 reg;
|
||||
s32 agc;
|
||||
s32 agc_0, agc_1, agc;
|
||||
s32 str;
|
||||
|
||||
reg = STV090x_READ_DEMOD(state, AGCIQIN1);
|
||||
agc = STV090x_GETFIELD_Px(reg, AGCIQ_VALUE_FIELD);
|
||||
agc_1 = STV090x_GETFIELD_Px(reg, AGCIQ_VALUE_FIELD);
|
||||
reg = STV090x_READ_DEMOD(state, AGCIQIN0);
|
||||
agc_0 = STV090x_GETFIELD_Px(reg, AGCIQ_VALUE_FIELD);
|
||||
agc = MAKEWORD16(agc_1, agc_0);
|
||||
|
||||
*strength = stv090x_table_lookup(stv090x_rf_tab, ARRAY_SIZE(stv090x_rf_tab) - 1, agc);
|
||||
str = stv090x_table_lookup(stv090x_rf_tab,
|
||||
ARRAY_SIZE(stv090x_rf_tab) - 1, agc);
|
||||
if (agc > stv090x_rf_tab[0].read)
|
||||
*strength = 5;
|
||||
str = 0;
|
||||
else if (agc < stv090x_rf_tab[ARRAY_SIZE(stv090x_rf_tab) - 1].read)
|
||||
*strength = -100;
|
||||
str = -100;
|
||||
*strength = (str + 100) * 0xFFFF / 100;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -3457,6 +3497,8 @@ static int stv090x_read_cnr(struct dvb_frontend *fe, u16 *cnr)
|
|||
u32 reg_0, reg_1, reg, i;
|
||||
s32 val_0, val_1, val = 0;
|
||||
u8 lock_f;
|
||||
s32 div;
|
||||
u32 last;
|
||||
|
||||
switch (state->delsys) {
|
||||
case STV090x_DVBS2:
|
||||
|
|
@ -3468,14 +3510,15 @@ static int stv090x_read_cnr(struct dvb_frontend *fe, u16 *cnr)
|
|||
reg_1 = STV090x_READ_DEMOD(state, NNOSPLHT1);
|
||||
val_1 = STV090x_GETFIELD_Px(reg_1, NOSPLHT_NORMED_FIELD);
|
||||
reg_0 = STV090x_READ_DEMOD(state, NNOSPLHT0);
|
||||
val_0 = STV090x_GETFIELD_Px(reg_1, NOSPLHT_NORMED_FIELD);
|
||||
val_0 = STV090x_GETFIELD_Px(reg_0, NOSPLHT_NORMED_FIELD);
|
||||
val += MAKEWORD16(val_1, val_0);
|
||||
msleep(1);
|
||||
}
|
||||
val /= 16;
|
||||
*cnr = stv090x_table_lookup(stv090x_s2cn_tab, ARRAY_SIZE(stv090x_s2cn_tab) - 1, val);
|
||||
if (val < stv090x_s2cn_tab[ARRAY_SIZE(stv090x_s2cn_tab) - 1].read)
|
||||
*cnr = 1000;
|
||||
last = ARRAY_SIZE(stv090x_s2cn_tab) - 1;
|
||||
div = stv090x_s2cn_tab[0].read -
|
||||
stv090x_s2cn_tab[last].read;
|
||||
*cnr = 0xFFFF - ((val * 0xFFFF) / div);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -3489,14 +3532,15 @@ static int stv090x_read_cnr(struct dvb_frontend *fe, u16 *cnr)
|
|||
reg_1 = STV090x_READ_DEMOD(state, NOSDATAT1);
|
||||
val_1 = STV090x_GETFIELD_Px(reg_1, NOSDATAT_UNNORMED_FIELD);
|
||||
reg_0 = STV090x_READ_DEMOD(state, NOSDATAT0);
|
||||
val_0 = STV090x_GETFIELD_Px(reg_1, NOSDATAT_UNNORMED_FIELD);
|
||||
val_0 = STV090x_GETFIELD_Px(reg_0, NOSDATAT_UNNORMED_FIELD);
|
||||
val += MAKEWORD16(val_1, val_0);
|
||||
msleep(1);
|
||||
}
|
||||
val /= 16;
|
||||
*cnr = stv090x_table_lookup(stv090x_s1cn_tab, ARRAY_SIZE(stv090x_s1cn_tab) - 1, val);
|
||||
if (val < stv090x_s2cn_tab[ARRAY_SIZE(stv090x_s1cn_tab) - 1].read)
|
||||
*cnr = 1000;
|
||||
last = ARRAY_SIZE(stv090x_s1cn_tab) - 1;
|
||||
div = stv090x_s1cn_tab[0].read -
|
||||
stv090x_s1cn_tab[last].read;
|
||||
*cnr = 0xFFFF - ((val * 0xFFFF) / div);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
|
@ -3732,6 +3776,8 @@ static int stv090x_ldpc_mode(struct stv090x_state *state, enum stv090x_mode ldpc
|
|||
{
|
||||
u32 reg = 0;
|
||||
|
||||
reg = stv090x_read_reg(state, STV090x_GENCFG);
|
||||
|
||||
switch (ldpc_mode) {
|
||||
case STV090x_DUAL:
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@
|
|||
|
||||
#define STV090x_IQPOWER_THRESHOLD 30
|
||||
#define STV090x_SEARCH_AGC2_TH_CUT20 700
|
||||
#define STV090x_SEARCH_AGC2_TH_CUT30 1200
|
||||
#define STV090x_SEARCH_AGC2_TH_CUT30 1400
|
||||
|
||||
#define STV090x_SEARCH_AGC2_TH(__ver) \
|
||||
((__ver <= 0x20) ? \
|
||||
|
|
@ -91,6 +91,7 @@
|
|||
STV090x_SEARCH_AGC2_TH_CUT30)
|
||||
|
||||
enum stv090x_signal_state {
|
||||
STV090x_NOAGC1,
|
||||
STV090x_NOCARRIER,
|
||||
STV090x_NODATA,
|
||||
STV090x_DATAOK,
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@
|
|||
#define STV090x_OFFST_OUTSERRS2_HZ_FIELD 5
|
||||
#define STV090x_WIDTH_OUTSERRS2_HZ_FIELD 1
|
||||
#define STV090x_OFFST_OUTSERRS3_HZ_FIELD 4
|
||||
#define STV090x_WIDTH_OUTPARRS3_HZ_FIELD 1
|
||||
#define STV090x_WIDTH_OUTSERRS3_HZ_FIELD 1
|
||||
#define STV090x_OFFST_OUTPARRS3_HZ_FIELD 3
|
||||
#define STV090x_WIDTH_OUTPARRS3_HZ_FIELD 1
|
||||
|
||||
|
|
@ -113,24 +113,24 @@
|
|||
#define STV090x_IRQMASK3 0xf124
|
||||
#define STV090x_OFFST_MPLL_LOCK_FIELD 5
|
||||
#define STV090x_WIDTH_MPLL_LOCK_FIELD 1
|
||||
#define STV090x_OFFST_MSTREAM_LCK_3_FIELD 2
|
||||
#define STV090x_WIDTH_MSTREAM_LCK_3_FIELD 3
|
||||
#define STV090x_OFFST_MSTREAM_LCK_2_FIELD 2
|
||||
#define STV090x_WIDTH_MSTREAM_LCK_2_FIELD 3
|
||||
#define STV090x_OFFST_MSTREAM_LCK_3_FIELD 4
|
||||
#define STV090x_WIDTH_MSTREAM_LCK_3_FIELD 1
|
||||
#define STV090x_OFFST_MSTREAM_LCK_2_FIELD 3
|
||||
#define STV090x_WIDTH_MSTREAM_LCK_2_FIELD 1
|
||||
#define STV090x_OFFST_MSTREAM_LCK_1_FIELD 2
|
||||
#define STV090x_WIDTH_MSTREAM_LCK_1_FIELD 3
|
||||
#define STV090x_WIDTH_MSTREAM_LCK_1_FIELD 1
|
||||
#define STV090x_OFFST_MDVBS1_PRF_2_FIELD 1
|
||||
#define STV090x_WIDTH_MDVBS1_PRF_2_FIELD 1
|
||||
#define STV090x_OFFST_MDVBS1_PRF_1_FIELD 0
|
||||
#define STV090x_WIDTH_MDVBS1_PRF_1_FIELD 1
|
||||
|
||||
#define STV090x_IRQMASK2 0xf125
|
||||
#define STV090x_OFFST_MSPY_ENDSIM_3_FIELD 5
|
||||
#define STV090x_WIDTH_MSPY_ENDSIM_3_FIELD 3
|
||||
#define STV090x_OFFST_MSPY_ENDSIM_2_FIELD 5
|
||||
#define STV090x_WIDTH_MSPY_ENDSIM_2_FIELD 3
|
||||
#define STV090x_OFFST_MSPY_ENDSIM_3_FIELD 7
|
||||
#define STV090x_WIDTH_MSPY_ENDSIM_3_FIELD 1
|
||||
#define STV090x_OFFST_MSPY_ENDSIM_2_FIELD 6
|
||||
#define STV090x_WIDTH_MSPY_ENDSIM_2_FIELD 1
|
||||
#define STV090x_OFFST_MSPY_ENDSIM_1_FIELD 5
|
||||
#define STV090x_WIDTH_MSPY_ENDSIM_1_FIELD 3
|
||||
#define STV090x_WIDTH_MSPY_ENDSIM_1_FIELD 1
|
||||
#define STV090x_OFFST_MPKTDEL_ERROR_2_FIELD 4
|
||||
#define STV090x_WIDTH_MPKTDEL_ERROR_2_FIELD 1
|
||||
#define STV090x_OFFST_MPKTDEL_LOCKB_2_FIELD 3
|
||||
|
|
@ -370,7 +370,7 @@
|
|||
#define STV090x_OFFST_SELX1RATIO_FIELD 5
|
||||
#define STV090x_WIDTH_SELX1RATIO_FIELD 1
|
||||
#define STV090x_OFFST_STOP_PLL_FIELD 3
|
||||
#define STV090x_WIDTH_SELX1RATIO_FIELD 1
|
||||
#define STV090x_WIDTH_STOP_PLL_FIELD 1
|
||||
#define STV090x_OFFST_BYPASSPLLFSK_FIELD 2
|
||||
#define STV090x_WIDTH_BYPASSPLLFSK_FIELD 1
|
||||
#define STV090x_OFFST_SELOSCI_FIELD 1
|
||||
|
|
@ -616,7 +616,7 @@
|
|||
#define STV090x_OFFST_Px_CONT_TONE_FIELD 4
|
||||
#define STV090x_WIDTH_Px_CONT_TONE_FIELD 1
|
||||
#define STV090x_OFFST_Px_FIFO_4BREADY_FIELD 3
|
||||
#define STV090x_WIDTH_Px_FIFO_4BREADY_FIELD 2
|
||||
#define STV090x_WIDTH_Px_FIFO_4BREADY_FIELD 1
|
||||
#define STV090x_OFFST_Px_FIFO_EMPTY_FIELD 2
|
||||
#define STV090x_WIDTH_Px_FIFO_EMPTY_FIELD 1
|
||||
#define STV090x_OFFST_Px_ABORT_DISRX_FIELD 0
|
||||
|
|
@ -847,12 +847,10 @@
|
|||
#define STV090x_WIDTH_Px_DVBS2_ENABLE_FIELD 1
|
||||
#define STV090x_OFFST_Px_DVBS1_ENABLE_FIELD 6
|
||||
#define STV090x_WIDTH_Px_DVBS1_ENABLE_FIELD 1
|
||||
#define STV090x_OFFST_Px_CFR_AUTOSCAN_FIELD 5 /* check */
|
||||
#define STV090x_WIDTH_Px_CFR_AUTOSCAN_FIELD 1
|
||||
#define STV090x_OFFST_Px_SCAN_ENABLE_FIELD 4 /* check */
|
||||
#define STV090x_OFFST_Px_SCAN_ENABLE_FIELD 4
|
||||
#define STV090x_WIDTH_Px_SCAN_ENABLE_FIELD 1
|
||||
#define STV090x_OFFST_Px_TUN_AUTOSCAN_FIELD 3
|
||||
#define STV090x_WIDTH_Px_TUN_AUTOSCAN_FIELD 1
|
||||
#define STV090x_OFFST_Px_CFR_AUTOSCAN_FIELD 3
|
||||
#define STV090x_WIDTH_Px_CFR_AUTOSCAN_FIELD 1
|
||||
#define STV090x_OFFST_Px_NOFORCE_RELOCK_FIELD 2
|
||||
#define STV090x_WIDTH_Px_NOFORCE_RELOCK_FIELD 1
|
||||
#define STV090x_OFFST_Px_TUN_RNG_FIELD 0
|
||||
|
|
@ -885,7 +883,7 @@
|
|||
#define STV090x_P2_DMDFLYW STV090x_Px_DMDFLYW(2)
|
||||
#define STV090x_OFFST_Px_I2C_IRQVAL_FIELD 4
|
||||
#define STV090x_WIDTH_Px_I2C_IRQVAL_FIELD 4
|
||||
#define STV090x_OFFST_Px_FLYWHEEL_CPT_FIELD 0 /* check */
|
||||
#define STV090x_OFFST_Px_FLYWHEEL_CPT_FIELD 0
|
||||
#define STV090x_WIDTH_Px_FLYWHEEL_CPT_FIELD 4
|
||||
|
||||
#define STV090x_Px_DSTATUS3(__x) (0xF41D - (__x - 1) * 0x200)
|
||||
|
|
@ -1048,12 +1046,12 @@
|
|||
#define STV090x_P1_CFRINC1 STV090x_Px_CFRINC1(1)
|
||||
#define STV090x_P2_CFRINC1 STV090x_Px_CFRINC1(2)
|
||||
#define STV090x_OFFST_Px_CFR_INC1_FIELD 0
|
||||
#define STV090x_WIDTH_Px_CFR_INC1_FIELD 7
|
||||
#define STV090x_WIDTH_Px_CFR_INC1_FIELD 7 /* check */
|
||||
|
||||
#define STV090x_Px_CFRINC0(__x) (0xF44B - (__x - 1) * 0x200)
|
||||
#define STV090x_P1_CFRINC0 STV090x_Px_CFRINC0(1)
|
||||
#define STV090x_P2_CFRINC0 STV090x_Px_CFRINC0(2)
|
||||
#define STV090x_OFFST_Px_CFR_INC0_FIELD 4
|
||||
#define STV090x_OFFST_Px_CFR_INC0_FIELD 4 /* check */
|
||||
#define STV090x_WIDTH_Px_CFR_INC0_FIELD 4
|
||||
|
||||
#define STV090x_Pn_CFRy(__x, __y) (0xF44E - (__x - 1) * 0x200 - __y * 0x1)
|
||||
|
|
@ -1145,14 +1143,14 @@
|
|||
#define STV090x_Px_SFRINIT1(__x) (0xF45E - (__x - 1) * 0x200)
|
||||
#define STV090x_P1_SFRINIT1 STV090x_Px_SFRINIT1(1)
|
||||
#define STV090x_P2_SFRINIT1 STV090x_Px_SFRINIT1(2)
|
||||
#define STV090x_OFFST_Px_SFR_INIT_FIELD 0
|
||||
#define STV090x_WIDTH_Px_SFR_INIT_FIELD 8
|
||||
#define STV090x_OFFST_Px_SFR_INIT1_FIELD 0
|
||||
#define STV090x_WIDTH_Px_SFR_INIT1_FIELD 7
|
||||
|
||||
#define STV090x_Px_SFRINIT0(__x) (0xF45F - (__x - 1) * 0x200)
|
||||
#define STV090x_P1_SFRINIT0 STV090x_Px_SFRINIT0(1)
|
||||
#define STV090x_P2_SFRINIT0 STV090x_Px_SFRINIT0(2)
|
||||
#define STV090x_OFFST_Px_SFR_INIT_FIELD 0
|
||||
#define STV090x_WIDTH_Px_SFR_INIT_FIELD 8
|
||||
#define STV090x_OFFST_Px_SFR_INIT0_FIELD 0
|
||||
#define STV090x_WIDTH_Px_SFR_INIT0_FIELD 8
|
||||
|
||||
#define STV090x_Px_SFRUP1(__x) (0xF460 - (__x - 1) * 0x200)
|
||||
#define STV090x_P1_SFRUP1 STV090x_Px_SFRUP1(1)
|
||||
|
|
@ -1178,7 +1176,7 @@
|
|||
#define STV090x_OFFST_Px_SYMB_FREQ_LOW0_FIELD 0
|
||||
#define STV090x_WIDTH_Px_SYMB_FREQ_LOW0_FIELD 8
|
||||
|
||||
#define STV090x_Px_SFRy(__x, __y) (0xF464 - (__x-1) * 0x200 + (3 - __y))
|
||||
#define STV090x_Px_SFRy(__x, __y) (0xF467 - (__x-1) * 0x200 - __y)
|
||||
#define STV090x_P1_SFR0 STV090x_Px_SFRy(1, 0)
|
||||
#define STV090x_P1_SFR1 STV090x_Px_SFRy(1, 1)
|
||||
#define STV090x_P1_SFR2 STV090x_Px_SFRy(1, 2)
|
||||
|
|
@ -1188,7 +1186,7 @@
|
|||
#define STV090x_P2_SFR2 STV090x_Px_SFRy(2, 2)
|
||||
#define STV090x_P2_SFR3 STV090x_Px_SFRy(2, 3)
|
||||
#define STV090x_OFFST_Px_SYMB_FREQ_FIELD 0
|
||||
#define STV090x_WIDTH_Px_SYMB_FREQ_FIELD 32
|
||||
#define STV090x_WIDTH_Px_SYMB_FREQ_FIELD 8
|
||||
|
||||
#define STV090x_Px_TMGREG2(__x) (0xF468 - (__x - 1) * 0x200)
|
||||
#define STV090x_P1_TMGREG2 STV090x_Px_TMGREG2(1)
|
||||
|
|
@ -1198,7 +1196,7 @@
|
|||
|
||||
#define STV090x_Px_TMGREG1(__x) (0xF469 - (__x - 1) * 0x200)
|
||||
#define STV090x_P1_TMGREG1 STV090x_Px_TMGREG1(1)
|
||||
#define STV090x_P2_TMGREG1 STV090x_Px_TMGREG1(2)
|
||||
#define STV090x_P2_TMGREG1 STV090x_Px_TMGREG1(2)
|
||||
#define STV090x_OFFST_Px_TMGREG_FIELD 0
|
||||
#define STV090x_WIDTH_Px_TMGREG_FIELD 8
|
||||
|
||||
|
|
@ -1230,7 +1228,7 @@
|
|||
#define STV090x_OFFST_Px_MU_EQUALDFE_FIELD 0
|
||||
#define STV090x_WIDTH_Px_MU_EQUALDFE_FIELD 3
|
||||
|
||||
#define STV090x_Px_EQUAIy(__x, __y) (0xf470 - (__x - 1) * 0x200 + (__y - 1))
|
||||
#define STV090x_Px_EQUAIy(__x, __y) (0xf470 - (__x-1) * 0x200 + 2 * (__y-1))
|
||||
#define STV090x_P1_EQUAI1 STV090x_Px_EQUAIy(1, 1)
|
||||
#define STV090x_P1_EQUAI2 STV090x_Px_EQUAIy(1, 2)
|
||||
#define STV090x_P1_EQUAI3 STV090x_Px_EQUAIy(1, 3)
|
||||
|
|
@ -1251,7 +1249,7 @@
|
|||
#define STV090x_OFFST_Px_EQUA_ACCIy_FIELD 0
|
||||
#define STV090x_WIDTH_Px_EQUA_ACCIy_FIELD 8
|
||||
|
||||
#define STV090x_Px_EQUAQy(__x, __y) (0xf471 - (__x - 1) * 0x200 + (__y - 1))
|
||||
#define STV090x_Px_EQUAQy(__x, __y) (0xf471 - (__x-1) * 0x200 + 2 * (__y-1))
|
||||
#define STV090x_P1_EQUAQ1 STV090x_Px_EQUAQy(1, 1)
|
||||
#define STV090x_P1_EQUAQ2 STV090x_Px_EQUAQy(1, 2)
|
||||
#define STV090x_P1_EQUAQ3 STV090x_Px_EQUAQy(1, 3)
|
||||
|
|
@ -1390,7 +1388,7 @@
|
|||
#define STV090x_OFFST_Px_CAR2S2_16A_ALPH_E_FIELD 0
|
||||
#define STV090x_WIDTH_Px_CAR2S2_16A_ALPH_E_FIELD 4
|
||||
|
||||
#define STV090x_Px_ACLC2S232A(__x) (0xf499 - (__x - 1) * 0x200)
|
||||
#define STV090x_Px_ACLC2S232A(__x) (0xf49A - (__x - 1) * 0x200)
|
||||
#define STV090x_P1_ACLC2S232A STV090x_Px_ACLC2S232A(1)
|
||||
#define STV090x_P2_ACLC2S232A STV090x_Px_ACLC2S232A(2)
|
||||
#define STV090x_OFFST_Px_CAR2S2_32A_ALPH_M_FIELD 4
|
||||
|
|
@ -1414,7 +1412,7 @@
|
|||
#define STV090x_OFFST_Px_CAR2S2_8_BETA_E_FIELD 0
|
||||
#define STV090x_WIDTH_Px_CAR2S2_8_BETA_E_FIELD 4
|
||||
|
||||
#define STV090x_Px_BCLC2S216A(__x) (0xf49d - (__x - 1) * 0x200)
|
||||
#define STV090x_Px_BCLC2S216A(__x) (0xf49e - (__x - 1) * 0x200)
|
||||
#define STV090x_P1_BCLC2S216A STV090x_Px_BCLC2S216A(1)
|
||||
#define STV090x_P2_BCLC2S216A STV090x_Px_BCLC2S216A(1)
|
||||
#define STV090x_OFFST_Px_CAR2S2_16A_BETA_M_FIELD 4
|
||||
|
|
@ -1422,7 +1420,7 @@
|
|||
#define STV090x_OFFST_Px_CAR2S2_16A_BETA_E_FIELD 0
|
||||
#define STV090x_WIDTH_Px_CAR2S2_16A_BETA_E_FIELD 4
|
||||
|
||||
#define STV090x_Px_BCLC2S232A(__x) (0xf49d - (__x - 1) * 0x200)
|
||||
#define STV090x_Px_BCLC2S232A(__x) (0xf49f - (__x - 1) * 0x200)
|
||||
#define STV090x_P1_BCLC2S232A STV090x_Px_BCLC2S232A(1)
|
||||
#define STV090x_P2_BCLC2S232A STV090x_Px_BCLC2S232A(1)
|
||||
#define STV090x_OFFST_Px_CAR2S2_32A_BETA_M_FIELD 4
|
||||
|
|
@ -1458,7 +1456,7 @@
|
|||
#define STV090x_P1_MODCODLST1 STV090x_Px_MODCODLST1(1)
|
||||
#define STV090x_P2_MODCODLST1 STV090x_Px_MODCODLST1(2)
|
||||
#define STV090x_OFFST_Px_DIS_MODCOD29_FIELD 4
|
||||
#define STV090x_WIDTH_Px_DIS_MODCOD29T_FIELD 4
|
||||
#define STV090x_WIDTH_Px_DIS_MODCOD29_FIELD 4
|
||||
#define STV090x_OFFST_Px_DIS_32PSK_9_10_FIELD 0
|
||||
#define STV090x_WIDTH_Px_DIS_32PSK_9_10_FIELD 4
|
||||
|
||||
|
|
@ -2180,7 +2178,7 @@
|
|||
#define STV090x_WIDTH_Px_TSFIFOSPEED_STORE_FIELD 1
|
||||
#define STV090x_OFFST_Px_DILXX_RESET_FIELD 5
|
||||
#define STV090x_WIDTH_Px_DILXX_RESET_FIELD 1
|
||||
#define STV090x_OFFST_Px_TSSERIAL_IMPOS_FIELD 5
|
||||
#define STV090x_OFFST_Px_TSSERIAL_IMPOS_FIELD 4
|
||||
#define STV090x_WIDTH_Px_TSSERIAL_IMPOS_FIELD 1
|
||||
#define STV090x_OFFST_Px_SCRAMBDETECT_FIELD 1
|
||||
#define STV090x_WIDTH_Px_SCRAMBDETECT_FIELD 1
|
||||
|
|
@ -2190,7 +2188,7 @@
|
|||
#define STV090x_P1_TSBITRATE1 STV090x_Px_TSBITRATEy(1, 1)
|
||||
#define STV090x_P2_TSBITRATE0 STV090x_Px_TSBITRATEy(2, 0)
|
||||
#define STV090x_P2_TSBITRATE1 STV090x_Px_TSBITRATEy(2, 1)
|
||||
#define STV090x_OFFST_Px_TSFIFO_BITRATE_FIELD 7
|
||||
#define STV090x_OFFST_Px_TSFIFO_BITRATE_FIELD 0
|
||||
#define STV090x_WIDTH_Px_TSFIFO_BITRATE_FIELD 8
|
||||
|
||||
#define STV090x_Px_ERRCTRL1(__x) (0xF598 - (__x - 1) * 0x200)
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ struct stv6110_priv {
|
|||
|
||||
u32 mclk;
|
||||
u8 clk_div;
|
||||
u8 gain;
|
||||
u8 regs[8];
|
||||
};
|
||||
|
||||
|
|
@ -255,7 +256,7 @@ static int stv6110_set_frequency(struct dvb_frontend *fe, u32 frequency)
|
|||
u8 ret = 0x04;
|
||||
u32 divider, ref, p, presc, i, result_freq, vco_freq;
|
||||
s32 p_calc, p_calc_opt = 1000, r_div, r_div_opt = 0, p_val;
|
||||
s32 srate; u8 gain;
|
||||
s32 srate;
|
||||
|
||||
dprintk("%s, freq=%d kHz, mclk=%d Hz\n", __func__,
|
||||
frequency, priv->mclk);
|
||||
|
|
@ -273,15 +274,8 @@ static int stv6110_set_frequency(struct dvb_frontend *fe, u32 frequency)
|
|||
} else
|
||||
srate = 15000000;
|
||||
|
||||
if (srate >= 15000000)
|
||||
gain = 3; /* +6 dB */
|
||||
else if (srate >= 5000000)
|
||||
gain = 3; /* +6 dB */
|
||||
else
|
||||
gain = 3; /* +6 dB */
|
||||
|
||||
priv->regs[RSTV6110_CTRL2] &= ~0x0f;
|
||||
priv->regs[RSTV6110_CTRL2] |= (gain & 0x0f);
|
||||
priv->regs[RSTV6110_CTRL2] |= (priv->gain & 0x0f);
|
||||
|
||||
if (frequency <= 1023000) {
|
||||
p = 1;
|
||||
|
|
@ -436,6 +430,7 @@ struct dvb_frontend *stv6110_attach(struct dvb_frontend *fe,
|
|||
priv->i2c = i2c;
|
||||
priv->mclk = config->mclk;
|
||||
priv->clk_div = config->clk_div;
|
||||
priv->gain = config->gain;
|
||||
|
||||
memcpy(&priv->regs, ®0[1], 8);
|
||||
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@
|
|||
struct stv6110_config {
|
||||
u8 i2c_address;
|
||||
u32 mclk;
|
||||
u8 gain;
|
||||
u8 clk_div; /* divisor value for the output clock */
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ static int stv6110x_set_frequency(struct dvb_frontend *fe, u32 frequency)
|
|||
{
|
||||
struct stv6110x_state *stv6110x = fe->tuner_priv;
|
||||
u32 rDiv, divider;
|
||||
s32 pVal, pCalc, rDivOpt = 0;
|
||||
s32 pVal, pCalc, rDivOpt = 0, pCalcOpt = 1000;
|
||||
u8 i;
|
||||
|
||||
STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_K, (REFCLOCK_MHz - 16));
|
||||
|
|
@ -121,8 +121,10 @@ static int stv6110x_set_frequency(struct dvb_frontend *fe, u32 frequency)
|
|||
for (rDiv = 0; rDiv <= 3; rDiv++) {
|
||||
pCalc = (REFCLOCK_kHz / 100) / R_DIV(rDiv);
|
||||
|
||||
if ((abs((s32)(pCalc - pVal))) < (abs((s32)(1000 - pVal))))
|
||||
if ((abs((s32)(pCalc - pVal))) < (abs((s32)(pCalcOpt - pVal))))
|
||||
rDivOpt = rDiv;
|
||||
|
||||
pCalcOpt = (REFCLOCK_kHz / 100) / R_DIV(rDivOpt);
|
||||
}
|
||||
|
||||
divider = (frequency * R_DIV(rDivOpt) * pVal) / REFCLOCK_kHz;
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@
|
|||
#include <linux/pci.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/freezer.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
#include "dvbdev.h"
|
||||
#include "dvb_demux.h"
|
||||
|
|
|
|||
|
|
@ -48,6 +48,60 @@ struct va1j5jf8007s_state {
|
|||
enum va1j5jf8007s_tune_state tune_state;
|
||||
};
|
||||
|
||||
static int va1j5jf8007s_read_snr(struct dvb_frontend *fe, u16 *snr)
|
||||
{
|
||||
struct va1j5jf8007s_state *state;
|
||||
u8 addr;
|
||||
int i;
|
||||
u8 write_buf[1], read_buf[1];
|
||||
struct i2c_msg msgs[2];
|
||||
s32 word, x1, x2, x3, x4, x5, y;
|
||||
|
||||
state = fe->demodulator_priv;
|
||||
addr = state->config->demod_address;
|
||||
|
||||
word = 0;
|
||||
for (i = 0; i < 2; i++) {
|
||||
write_buf[0] = 0xbc + i;
|
||||
|
||||
msgs[0].addr = addr;
|
||||
msgs[0].flags = 0;
|
||||
msgs[0].len = sizeof(write_buf);
|
||||
msgs[0].buf = write_buf;
|
||||
|
||||
msgs[1].addr = addr;
|
||||
msgs[1].flags = I2C_M_RD;
|
||||
msgs[1].len = sizeof(read_buf);
|
||||
msgs[1].buf = read_buf;
|
||||
|
||||
if (i2c_transfer(state->adap, msgs, 2) != 2)
|
||||
return -EREMOTEIO;
|
||||
|
||||
word <<= 8;
|
||||
word |= read_buf[0];
|
||||
}
|
||||
|
||||
word -= 3000;
|
||||
if (word < 0)
|
||||
word = 0;
|
||||
|
||||
x1 = int_sqrt(word << 16) * ((15625ll << 21) / 1000000);
|
||||
x2 = (s64)x1 * x1 >> 31;
|
||||
x3 = (s64)x2 * x1 >> 31;
|
||||
x4 = (s64)x2 * x2 >> 31;
|
||||
x5 = (s64)x4 * x1 >> 31;
|
||||
|
||||
y = (58857ll << 23) / 1000;
|
||||
y -= (s64)x1 * ((89565ll << 24) / 1000) >> 30;
|
||||
y += (s64)x2 * ((88977ll << 24) / 1000) >> 28;
|
||||
y -= (s64)x3 * ((50259ll << 25) / 1000) >> 27;
|
||||
y += (s64)x4 * ((14341ll << 27) / 1000) >> 27;
|
||||
y -= (s64)x5 * ((16346ll << 30) / 10000) >> 28;
|
||||
|
||||
*snr = y < 0 ? 0 : y >> 15;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int va1j5jf8007s_get_frontend_algo(struct dvb_frontend *fe)
|
||||
{
|
||||
return DVBFE_ALGO_HW;
|
||||
|
|
@ -337,7 +391,7 @@ va1j5jf8007s_tune(struct dvb_frontend *fe,
|
|||
{
|
||||
struct va1j5jf8007s_state *state;
|
||||
int ret;
|
||||
int lock;
|
||||
int lock = 0;
|
||||
|
||||
state = fe->demodulator_priv;
|
||||
|
||||
|
|
@ -536,6 +590,7 @@ static struct dvb_frontend_ops va1j5jf8007s_ops = {
|
|||
FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO,
|
||||
},
|
||||
|
||||
.read_snr = va1j5jf8007s_read_snr,
|
||||
.get_frontend_algo = va1j5jf8007s_get_frontend_algo,
|
||||
.read_status = va1j5jf8007s_read_status,
|
||||
.tune = va1j5jf8007s_tune,
|
||||
|
|
|
|||
|
|
@ -46,6 +46,52 @@ struct va1j5jf8007t_state {
|
|||
enum va1j5jf8007t_tune_state tune_state;
|
||||
};
|
||||
|
||||
static int va1j5jf8007t_read_snr(struct dvb_frontend *fe, u16 *snr)
|
||||
{
|
||||
struct va1j5jf8007t_state *state;
|
||||
u8 addr;
|
||||
int i;
|
||||
u8 write_buf[1], read_buf[1];
|
||||
struct i2c_msg msgs[2];
|
||||
s32 word, x, y;
|
||||
|
||||
state = fe->demodulator_priv;
|
||||
addr = state->config->demod_address;
|
||||
|
||||
word = 0;
|
||||
for (i = 0; i < 3; i++) {
|
||||
write_buf[0] = 0x8b + i;
|
||||
|
||||
msgs[0].addr = addr;
|
||||
msgs[0].flags = 0;
|
||||
msgs[0].len = sizeof(write_buf);
|
||||
msgs[0].buf = write_buf;
|
||||
|
||||
msgs[1].addr = addr;
|
||||
msgs[1].flags = I2C_M_RD;
|
||||
msgs[1].len = sizeof(read_buf);
|
||||
msgs[1].buf = read_buf;
|
||||
|
||||
if (i2c_transfer(state->adap, msgs, 2) != 2)
|
||||
return -EREMOTEIO;
|
||||
|
||||
word <<= 8;
|
||||
word |= read_buf[0];
|
||||
}
|
||||
|
||||
if (!word)
|
||||
return -EIO;
|
||||
|
||||
x = 10 * (intlog10(0x540000 * 100 / word) - (2 << 24));
|
||||
y = (24ll << 46) / 1000000;
|
||||
y = ((s64)y * x >> 30) - (16ll << 40) / 10000;
|
||||
y = ((s64)y * x >> 29) + (398ll << 35) / 10000;
|
||||
y = ((s64)y * x >> 30) + (5491ll << 29) / 10000;
|
||||
y = ((s64)y * x >> 30) + (30965ll << 23) / 10000;
|
||||
*snr = y >> 15;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int va1j5jf8007t_get_frontend_algo(struct dvb_frontend *fe)
|
||||
{
|
||||
return DVBFE_ALGO_HW;
|
||||
|
|
@ -224,7 +270,7 @@ va1j5jf8007t_tune(struct dvb_frontend *fe,
|
|||
{
|
||||
struct va1j5jf8007t_state *state;
|
||||
int ret;
|
||||
int lock, retry;
|
||||
int lock = 0, retry = 0;
|
||||
|
||||
state = fe->demodulator_priv;
|
||||
|
||||
|
|
@ -393,6 +439,7 @@ static struct dvb_frontend_ops va1j5jf8007t_ops = {
|
|||
FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO,
|
||||
},
|
||||
|
||||
.read_snr = va1j5jf8007t_read_snr,
|
||||
.get_frontend_algo = va1j5jf8007t_get_frontend_algo,
|
||||
.read_status = va1j5jf8007t_read_status,
|
||||
.tune = va1j5jf8007t_tune,
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ static struct sms_board sms_boards[] = {
|
|||
},
|
||||
};
|
||||
|
||||
struct sms_board *sms_get_board(int id)
|
||||
struct sms_board *sms_get_board(unsigned id)
|
||||
{
|
||||
BUG_ON(id >= ARRAY_SIZE(sms_boards));
|
||||
|
||||
|
|
@ -294,6 +294,8 @@ int sms_board_load_modules(int id)
|
|||
case SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A:
|
||||
case SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B:
|
||||
case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
|
||||
case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
|
||||
case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
|
||||
request_module("smsdvb");
|
||||
break;
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ struct sms_board {
|
|||
int led_power, led_hi, led_lo, lna_ctrl, rf_switch;
|
||||
};
|
||||
|
||||
struct sms_board *sms_get_board(int id);
|
||||
struct sms_board *sms_get_board(unsigned id);
|
||||
|
||||
extern struct smscore_device_t *coredev;
|
||||
|
||||
|
|
|
|||
|
|
@ -1373,7 +1373,7 @@ static int GetGpioPinParams(u32 PinNum, u32 *pTranslatedPinNum,
|
|||
|
||||
*pGroupCfg = 1;
|
||||
|
||||
if (PinNum >= 0 && PinNum <= 1) {
|
||||
if (PinNum <= 1) {
|
||||
*pTranslatedPinNum = 0;
|
||||
*pGroupNum = 9;
|
||||
*pGroupCfg = 2;
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ struct smssdio_device {
|
|||
|
||||
static int smssdio_sendrequest(void *context, void *buffer, size_t size)
|
||||
{
|
||||
int ret;
|
||||
int ret = 0;
|
||||
struct smssdio_device *smsdev;
|
||||
|
||||
smsdev = context;
|
||||
|
|
|
|||
|
|
@ -1055,7 +1055,7 @@ static const struct stb0899_s1_reg knc1_stb0899_s1_init_3[] = {
|
|||
{ STB0899_TSCFGH , 0x0c },
|
||||
{ STB0899_TSCFGM , 0x00 },
|
||||
{ STB0899_TSCFGL , 0x0c },
|
||||
{ STB0899_TSOUT , 0x0d }, /* 0x0d for CAM */
|
||||
{ STB0899_TSOUT , 0x4d }, /* 0x0d for CAM */
|
||||
{ STB0899_RSSYNCDEL , 0x00 },
|
||||
{ STB0899_TSINHDELH , 0x02 },
|
||||
{ STB0899_TSINHDELM , 0x00 },
|
||||
|
|
|
|||
|
|
@ -178,7 +178,7 @@ static void msp430_ir_interrupt(unsigned long data)
|
|||
if (budget_ci->ir.last_raw != raw || !timer_pending(&budget_ci->ir.timer_keyup)) {
|
||||
ir_input_nokey(dev, &budget_ci->ir.state);
|
||||
ir_input_keydown(dev, &budget_ci->ir.state,
|
||||
budget_ci->ir.ir_key, raw);
|
||||
budget_ci->ir.ir_key);
|
||||
budget_ci->ir.last_raw = raw;
|
||||
}
|
||||
|
||||
|
|
@ -224,8 +224,10 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
|
|||
case 0x1011:
|
||||
case 0x1012:
|
||||
/* The hauppauge keymap is a superset of these remotes */
|
||||
ir_input_init(input_dev, &budget_ci->ir.state,
|
||||
error = ir_input_init(input_dev, &budget_ci->ir.state,
|
||||
IR_TYPE_RC5, &ir_codes_hauppauge_new_table);
|
||||
if (error < 0)
|
||||
goto out2;
|
||||
|
||||
if (rc5_device < 0)
|
||||
budget_ci->ir.rc5_device = 0x1f;
|
||||
|
|
@ -236,8 +238,10 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
|
|||
case 0x1017:
|
||||
case 0x101a:
|
||||
/* for the Technotrend 1500 bundled remote */
|
||||
ir_input_init(input_dev, &budget_ci->ir.state,
|
||||
error = ir_input_init(input_dev, &budget_ci->ir.state,
|
||||
IR_TYPE_RC5, &ir_codes_tt_1500_table);
|
||||
if (error < 0)
|
||||
goto out2;
|
||||
|
||||
if (rc5_device < 0)
|
||||
budget_ci->ir.rc5_device = IR_DEVICE_ANY;
|
||||
|
|
@ -246,8 +250,10 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
|
|||
break;
|
||||
default:
|
||||
/* unknown remote */
|
||||
ir_input_init(input_dev, &budget_ci->ir.state,
|
||||
error = ir_input_init(input_dev, &budget_ci->ir.state,
|
||||
IR_TYPE_RC5, &ir_codes_budget_ci_old_table);
|
||||
if (error < 0)
|
||||
goto out2;
|
||||
|
||||
if (rc5_device < 0)
|
||||
budget_ci->ir.rc5_device = IR_DEVICE_ANY;
|
||||
|
|
@ -280,6 +286,7 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
|
|||
return 0;
|
||||
|
||||
out2:
|
||||
ir_input_free(input_dev);
|
||||
input_free_device(input_dev);
|
||||
out1:
|
||||
return error;
|
||||
|
|
@ -297,6 +304,7 @@ static void msp430_ir_deinit(struct budget_ci *budget_ci)
|
|||
del_timer_sync(&dev->timer);
|
||||
ir_input_nokey(dev, &budget_ci->ir.state);
|
||||
|
||||
ir_input_free(dev);
|
||||
input_unregister_device(dev);
|
||||
}
|
||||
|
||||
|
|
@ -1248,7 +1256,7 @@ static const struct stb0899_s1_reg tt3200_stb0899_s1_init_3[] = {
|
|||
{ STB0899_TSCFGH , 0x0c },
|
||||
{ STB0899_TSCFGM , 0x00 },
|
||||
{ STB0899_TSCFGL , 0x0c },
|
||||
{ STB0899_TSOUT , 0x0d }, /* 0x0d for CAM */
|
||||
{ STB0899_TSOUT , 0x4d }, /* 0x0d for CAM */
|
||||
{ STB0899_RSSYNCDEL , 0x00 },
|
||||
{ STB0899_TSINHDELH , 0x02 },
|
||||
{ STB0899_TSINHDELM , 0x00 },
|
||||
|
|
|
|||
|
|
@ -1198,7 +1198,7 @@ static int ttusb_init_rc( struct ttusb_dec *dec)
|
|||
int err;
|
||||
|
||||
usb_make_path(dec->udev, dec->rc_phys, sizeof(dec->rc_phys));
|
||||
strlcpy(dec->rc_phys, "/input0", sizeof(dec->rc_phys));
|
||||
strlcat(dec->rc_phys, "/input0", sizeof(dec->rc_phys));
|
||||
|
||||
input_dev = input_allocate_device();
|
||||
if (!input_dev)
|
||||
|
|
|
|||
|
|
@ -419,4 +419,16 @@ config RADIO_TEA5764_XTAL
|
|||
Say Y here if TEA5764 have a 32768 Hz crystal in circuit, say N
|
||||
here if TEA5764 reference frequency is connected in FREQIN.
|
||||
|
||||
config RADIO_TEF6862
|
||||
tristate "TEF6862 Car Radio Enhanced Selectivity Tuner"
|
||||
depends on I2C && VIDEO_V4L2
|
||||
---help---
|
||||
Say Y here if you want to use the TEF6862 Car Radio Enhanced
|
||||
Selectivity Tuner, found for instance on the Russellville development
|
||||
board. On the russellville the device is connected to internal
|
||||
timberdale I2C bus.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called TEF6862.
|
||||
|
||||
endif # RADIO_ADAPTERS
|
||||
|
|
|
|||
|
|
@ -23,5 +23,6 @@ obj-$(CONFIG_USB_DSBR) += dsbr100.o
|
|||
obj-$(CONFIG_RADIO_SI470X) += si470x/
|
||||
obj-$(CONFIG_USB_MR800) += radio-mr800.o
|
||||
obj-$(CONFIG_RADIO_TEA5764) += radio-tea5764.o
|
||||
obj-$(CONFIG_RADIO_TEF6862) += tef6862.o
|
||||
|
||||
EXTRA_CFLAGS += -Isound
|
||||
|
|
|
|||
|
|
@ -85,6 +85,9 @@ MODULE_LICENSE("GPL");
|
|||
#define amradio_dev_warn(dev, fmt, arg...) \
|
||||
dev_warn(dev, MR800_DRIVER_NAME " - " fmt, ##arg)
|
||||
|
||||
#define amradio_dev_err(dev, fmt, arg...) \
|
||||
dev_err(dev, MR800_DRIVER_NAME " - " fmt, ##arg)
|
||||
|
||||
/* Probably USB_TIMEOUT should be modified in module parameter */
|
||||
#define BUFFER_LENGTH 8
|
||||
#define USB_TIMEOUT 500
|
||||
|
|
@ -129,18 +132,20 @@ static int usb_amradio_resume(struct usb_interface *intf);
|
|||
struct amradio_device {
|
||||
/* reference to USB and video device */
|
||||
struct usb_device *usbdev;
|
||||
struct video_device *videodev;
|
||||
struct usb_interface *intf;
|
||||
struct video_device videodev;
|
||||
struct v4l2_device v4l2_dev;
|
||||
|
||||
unsigned char *buffer;
|
||||
struct mutex lock; /* buffer locking */
|
||||
int curfreq;
|
||||
int stereo;
|
||||
int users;
|
||||
int removed;
|
||||
int muted;
|
||||
int initialized;
|
||||
};
|
||||
|
||||
#define vdev_to_amradio(r) container_of(r, struct amradio_device, videodev)
|
||||
|
||||
/* USB Device ID List */
|
||||
static struct usb_device_id usb_amradio_device_table[] = {
|
||||
{USB_DEVICE_AND_INTERFACE_INFO(USB_AMRADIO_VENDOR, USB_AMRADIO_PRODUCT,
|
||||
|
|
@ -159,7 +164,7 @@ static struct usb_driver usb_amradio_driver = {
|
|||
.resume = usb_amradio_resume,
|
||||
.reset_resume = usb_amradio_resume,
|
||||
.id_table = usb_amradio_device_table,
|
||||
.supports_autosuspend = 0,
|
||||
.supports_autosuspend = 1,
|
||||
};
|
||||
|
||||
/* switch on/off the radio. Send 8 bytes to device */
|
||||
|
|
@ -168,11 +173,7 @@ static int amradio_set_mute(struct amradio_device *radio, char argument)
|
|||
int retval;
|
||||
int size;
|
||||
|
||||
/* safety check */
|
||||
if (radio->removed)
|
||||
return -EIO;
|
||||
|
||||
mutex_lock(&radio->lock);
|
||||
BUG_ON(!mutex_is_locked(&radio->lock));
|
||||
|
||||
radio->buffer[0] = 0x00;
|
||||
radio->buffer[1] = 0x55;
|
||||
|
|
@ -187,14 +188,12 @@ static int amradio_set_mute(struct amradio_device *radio, char argument)
|
|||
(void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
|
||||
|
||||
if (retval < 0 || size != BUFFER_LENGTH) {
|
||||
mutex_unlock(&radio->lock);
|
||||
amradio_dev_warn(&radio->videodev.dev, "set mute failed\n");
|
||||
return retval;
|
||||
}
|
||||
|
||||
radio->muted = argument;
|
||||
|
||||
mutex_unlock(&radio->lock);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
@ -205,11 +204,7 @@ static int amradio_setfreq(struct amradio_device *radio, int freq)
|
|||
int size;
|
||||
unsigned short freq_send = 0x10 + (freq >> 3) / 25;
|
||||
|
||||
/* safety check */
|
||||
if (radio->removed)
|
||||
return -EIO;
|
||||
|
||||
mutex_lock(&radio->lock);
|
||||
BUG_ON(!mutex_is_locked(&radio->lock));
|
||||
|
||||
radio->buffer[0] = 0x00;
|
||||
radio->buffer[1] = 0x55;
|
||||
|
|
@ -223,10 +218,8 @@ static int amradio_setfreq(struct amradio_device *radio, int freq)
|
|||
retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
|
||||
(void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
|
||||
|
||||
if (retval < 0 || size != BUFFER_LENGTH) {
|
||||
mutex_unlock(&radio->lock);
|
||||
return retval;
|
||||
}
|
||||
if (retval < 0 || size != BUFFER_LENGTH)
|
||||
goto out_err;
|
||||
|
||||
/* frequency is calculated from freq_send and placed in first 2 bytes */
|
||||
radio->buffer[0] = (freq_send >> 8) & 0xff;
|
||||
|
|
@ -240,13 +233,15 @@ static int amradio_setfreq(struct amradio_device *radio, int freq)
|
|||
retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
|
||||
(void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
|
||||
|
||||
if (retval < 0 || size != BUFFER_LENGTH) {
|
||||
mutex_unlock(&radio->lock);
|
||||
return retval;
|
||||
}
|
||||
if (retval < 0 || size != BUFFER_LENGTH)
|
||||
goto out_err;
|
||||
|
||||
mutex_unlock(&radio->lock);
|
||||
radio->curfreq = freq;
|
||||
goto out;
|
||||
|
||||
out_err:
|
||||
amradio_dev_warn(&radio->videodev.dev, "set frequency failed\n");
|
||||
out:
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
@ -255,11 +250,7 @@ static int amradio_set_stereo(struct amradio_device *radio, char argument)
|
|||
int retval;
|
||||
int size;
|
||||
|
||||
/* safety check */
|
||||
if (radio->removed)
|
||||
return -EIO;
|
||||
|
||||
mutex_lock(&radio->lock);
|
||||
BUG_ON(!mutex_is_locked(&radio->lock));
|
||||
|
||||
radio->buffer[0] = 0x00;
|
||||
radio->buffer[1] = 0x55;
|
||||
|
|
@ -274,14 +265,14 @@ static int amradio_set_stereo(struct amradio_device *radio, char argument)
|
|||
(void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
|
||||
|
||||
if (retval < 0 || size != BUFFER_LENGTH) {
|
||||
radio->stereo = -1;
|
||||
mutex_unlock(&radio->lock);
|
||||
amradio_dev_warn(&radio->videodev.dev, "set stereo failed\n");
|
||||
return retval;
|
||||
}
|
||||
|
||||
radio->stereo = 1;
|
||||
|
||||
mutex_unlock(&radio->lock);
|
||||
if (argument == WANT_STEREO)
|
||||
radio->stereo = 1;
|
||||
else
|
||||
radio->stereo = 0;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
|
@ -296,19 +287,19 @@ static void usb_amradio_disconnect(struct usb_interface *intf)
|
|||
struct amradio_device *radio = usb_get_intfdata(intf);
|
||||
|
||||
mutex_lock(&radio->lock);
|
||||
radio->removed = 1;
|
||||
radio->usbdev = NULL;
|
||||
mutex_unlock(&radio->lock);
|
||||
|
||||
usb_set_intfdata(intf, NULL);
|
||||
video_unregister_device(radio->videodev);
|
||||
v4l2_device_disconnect(&radio->v4l2_dev);
|
||||
video_unregister_device(&radio->videodev);
|
||||
}
|
||||
|
||||
/* vidioc_querycap - query device capabilities */
|
||||
static int vidioc_querycap(struct file *file, void *priv,
|
||||
struct v4l2_capability *v)
|
||||
{
|
||||
struct amradio_device *radio = video_drvdata(file);
|
||||
struct amradio_device *radio = file->private_data;
|
||||
|
||||
strlcpy(v->driver, "radio-mr800", sizeof(v->driver));
|
||||
strlcpy(v->card, "AverMedia MR 800 USB FM Radio", sizeof(v->card));
|
||||
|
|
@ -322,13 +313,9 @@ static int vidioc_querycap(struct file *file, void *priv,
|
|||
static int vidioc_g_tuner(struct file *file, void *priv,
|
||||
struct v4l2_tuner *v)
|
||||
{
|
||||
struct amradio_device *radio = video_get_drvdata(video_devdata(file));
|
||||
struct amradio_device *radio = file->private_data;
|
||||
int retval;
|
||||
|
||||
/* safety check */
|
||||
if (radio->removed)
|
||||
return -EIO;
|
||||
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
|
||||
|
|
@ -341,9 +328,6 @@ static int vidioc_g_tuner(struct file *file, void *priv,
|
|||
* amradio_set_stereo shouldn't be here
|
||||
*/
|
||||
retval = amradio_set_stereo(radio, WANT_STEREO);
|
||||
if (retval < 0)
|
||||
amradio_dev_warn(&radio->videodev->dev,
|
||||
"set stereo failed\n");
|
||||
|
||||
strcpy(v->name, "FM");
|
||||
v->type = V4L2_TUNER_RADIO;
|
||||
|
|
@ -357,19 +341,16 @@ static int vidioc_g_tuner(struct file *file, void *priv,
|
|||
v->audmode = V4L2_TUNER_MODE_MONO;
|
||||
v->signal = 0xffff; /* Can't get the signal strength, sad.. */
|
||||
v->afc = 0; /* Don't know what is this */
|
||||
return 0;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* vidioc_s_tuner - set tuner attributes */
|
||||
static int vidioc_s_tuner(struct file *file, void *priv,
|
||||
struct v4l2_tuner *v)
|
||||
{
|
||||
struct amradio_device *radio = video_get_drvdata(video_devdata(file));
|
||||
int retval;
|
||||
|
||||
/* safety check */
|
||||
if (radio->removed)
|
||||
return -EIO;
|
||||
struct amradio_device *radio = file->private_data;
|
||||
int retval = -EINVAL;
|
||||
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
|
|
@ -378,57 +359,33 @@ static int vidioc_s_tuner(struct file *file, void *priv,
|
|||
switch (v->audmode) {
|
||||
case V4L2_TUNER_MODE_MONO:
|
||||
retval = amradio_set_stereo(radio, WANT_MONO);
|
||||
if (retval < 0)
|
||||
amradio_dev_warn(&radio->videodev->dev,
|
||||
"set mono failed\n");
|
||||
break;
|
||||
case V4L2_TUNER_MODE_STEREO:
|
||||
retval = amradio_set_stereo(radio, WANT_STEREO);
|
||||
if (retval < 0)
|
||||
amradio_dev_warn(&radio->videodev->dev,
|
||||
"set stereo failed\n");
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* vidioc_s_frequency - set tuner radio frequency */
|
||||
static int vidioc_s_frequency(struct file *file, void *priv,
|
||||
struct v4l2_frequency *f)
|
||||
{
|
||||
struct amradio_device *radio = video_get_drvdata(video_devdata(file));
|
||||
int retval;
|
||||
struct amradio_device *radio = file->private_data;
|
||||
|
||||
/* safety check */
|
||||
if (radio->removed)
|
||||
return -EIO;
|
||||
|
||||
mutex_lock(&radio->lock);
|
||||
radio->curfreq = f->frequency;
|
||||
mutex_unlock(&radio->lock);
|
||||
|
||||
retval = amradio_setfreq(radio, radio->curfreq);
|
||||
if (retval < 0)
|
||||
amradio_dev_warn(&radio->videodev->dev,
|
||||
"set frequency failed\n");
|
||||
return 0;
|
||||
return amradio_setfreq(radio, f->frequency);
|
||||
}
|
||||
|
||||
/* vidioc_g_frequency - get tuner radio frequency */
|
||||
static int vidioc_g_frequency(struct file *file, void *priv,
|
||||
struct v4l2_frequency *f)
|
||||
{
|
||||
struct amradio_device *radio = video_get_drvdata(video_devdata(file));
|
||||
|
||||
/* safety check */
|
||||
if (radio->removed)
|
||||
return -EIO;
|
||||
struct amradio_device *radio = file->private_data;
|
||||
|
||||
f->type = V4L2_TUNER_RADIO;
|
||||
f->frequency = radio->curfreq;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -448,17 +405,14 @@ static int vidioc_queryctrl(struct file *file, void *priv,
|
|||
static int vidioc_g_ctrl(struct file *file, void *priv,
|
||||
struct v4l2_control *ctrl)
|
||||
{
|
||||
struct amradio_device *radio = video_get_drvdata(video_devdata(file));
|
||||
|
||||
/* safety check */
|
||||
if (radio->removed)
|
||||
return -EIO;
|
||||
struct amradio_device *radio = file->private_data;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
ctrl->value = radio->muted;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
@ -466,33 +420,20 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
|
|||
static int vidioc_s_ctrl(struct file *file, void *priv,
|
||||
struct v4l2_control *ctrl)
|
||||
{
|
||||
struct amradio_device *radio = video_get_drvdata(video_devdata(file));
|
||||
int retval;
|
||||
|
||||
/* safety check */
|
||||
if (radio->removed)
|
||||
return -EIO;
|
||||
struct amradio_device *radio = file->private_data;
|
||||
int retval = -EINVAL;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
if (ctrl->value) {
|
||||
if (ctrl->value)
|
||||
retval = amradio_set_mute(radio, AMRADIO_STOP);
|
||||
if (retval < 0) {
|
||||
amradio_dev_warn(&radio->videodev->dev,
|
||||
"amradio_stop failed\n");
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
else
|
||||
retval = amradio_set_mute(radio, AMRADIO_START);
|
||||
if (retval < 0) {
|
||||
amradio_dev_warn(&radio->videodev->dev,
|
||||
"amradio_start failed\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
break;
|
||||
}
|
||||
return -EINVAL;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* vidioc_g_audio - get audio attributes */
|
||||
|
|
@ -531,75 +472,108 @@ static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int usb_amradio_init(struct amradio_device *radio)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval = amradio_set_mute(radio, AMRADIO_STOP);
|
||||
if (retval)
|
||||
goto out_err;
|
||||
|
||||
retval = amradio_set_stereo(radio, WANT_STEREO);
|
||||
if (retval)
|
||||
goto out_err;
|
||||
|
||||
radio->initialized = 1;
|
||||
goto out;
|
||||
|
||||
out_err:
|
||||
amradio_dev_err(&radio->videodev.dev, "initialization failed\n");
|
||||
out:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* open device - amradio_start() and amradio_setfreq() */
|
||||
static int usb_amradio_open(struct file *file)
|
||||
{
|
||||
struct amradio_device *radio = video_get_drvdata(video_devdata(file));
|
||||
int retval;
|
||||
struct amradio_device *radio = vdev_to_amradio(video_devdata(file));
|
||||
int retval = 0;
|
||||
|
||||
lock_kernel();
|
||||
mutex_lock(&radio->lock);
|
||||
|
||||
radio->users = 1;
|
||||
radio->muted = 1;
|
||||
|
||||
retval = amradio_set_mute(radio, AMRADIO_START);
|
||||
if (retval < 0) {
|
||||
amradio_dev_warn(&radio->videodev->dev,
|
||||
"radio did not start up properly\n");
|
||||
radio->users = 0;
|
||||
unlock_kernel();
|
||||
return -EIO;
|
||||
if (!radio->usbdev) {
|
||||
retval = -EIO;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
retval = amradio_set_stereo(radio, WANT_STEREO);
|
||||
if (retval < 0)
|
||||
amradio_dev_warn(&radio->videodev->dev,
|
||||
"set stereo failed\n");
|
||||
file->private_data = radio;
|
||||
retval = usb_autopm_get_interface(radio->intf);
|
||||
if (retval)
|
||||
goto unlock;
|
||||
|
||||
retval = amradio_setfreq(radio, radio->curfreq);
|
||||
if (retval < 0)
|
||||
amradio_dev_warn(&radio->videodev->dev,
|
||||
"set frequency failed\n");
|
||||
if (unlikely(!radio->initialized)) {
|
||||
retval = usb_amradio_init(radio);
|
||||
if (retval)
|
||||
usb_autopm_put_interface(radio->intf);
|
||||
}
|
||||
|
||||
unlock_kernel();
|
||||
return 0;
|
||||
unlock:
|
||||
mutex_unlock(&radio->lock);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*close device */
|
||||
static int usb_amradio_close(struct file *file)
|
||||
{
|
||||
struct amradio_device *radio = video_get_drvdata(video_devdata(file));
|
||||
int retval;
|
||||
|
||||
if (!radio)
|
||||
return -ENODEV;
|
||||
struct amradio_device *radio = file->private_data;
|
||||
int retval = 0;
|
||||
|
||||
mutex_lock(&radio->lock);
|
||||
radio->users = 0;
|
||||
mutex_unlock(&radio->lock);
|
||||
|
||||
if (!radio->removed) {
|
||||
retval = amradio_set_mute(radio, AMRADIO_STOP);
|
||||
if (retval < 0)
|
||||
amradio_dev_warn(&radio->videodev->dev,
|
||||
"amradio_stop failed\n");
|
||||
if (!radio->usbdev)
|
||||
retval = -EIO;
|
||||
else
|
||||
usb_autopm_put_interface(radio->intf);
|
||||
|
||||
mutex_unlock(&radio->lock);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static long usb_amradio_ioctl(struct file *file, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
struct amradio_device *radio = file->private_data;
|
||||
long retval = 0;
|
||||
|
||||
mutex_lock(&radio->lock);
|
||||
|
||||
if (!radio->usbdev) {
|
||||
retval = -EIO;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
return 0;
|
||||
retval = video_ioctl2(file, cmd, arg);
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&radio->lock);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Suspend device - stop device. Need to be checked and fixed */
|
||||
static int usb_amradio_suspend(struct usb_interface *intf, pm_message_t message)
|
||||
{
|
||||
struct amradio_device *radio = usb_get_intfdata(intf);
|
||||
int retval;
|
||||
|
||||
retval = amradio_set_mute(radio, AMRADIO_STOP);
|
||||
if (retval < 0)
|
||||
dev_warn(&intf->dev, "amradio_stop failed\n");
|
||||
mutex_lock(&radio->lock);
|
||||
|
||||
if (!radio->muted && radio->initialized) {
|
||||
amradio_set_mute(radio, AMRADIO_STOP);
|
||||
radio->muted = 0;
|
||||
}
|
||||
|
||||
dev_info(&intf->dev, "going into suspend..\n");
|
||||
|
||||
mutex_unlock(&radio->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -607,14 +581,26 @@ static int usb_amradio_suspend(struct usb_interface *intf, pm_message_t message)
|
|||
static int usb_amradio_resume(struct usb_interface *intf)
|
||||
{
|
||||
struct amradio_device *radio = usb_get_intfdata(intf);
|
||||
int retval;
|
||||
|
||||
retval = amradio_set_mute(radio, AMRADIO_START);
|
||||
if (retval < 0)
|
||||
dev_warn(&intf->dev, "amradio_start failed\n");
|
||||
mutex_lock(&radio->lock);
|
||||
|
||||
if (unlikely(!radio->initialized))
|
||||
goto unlock;
|
||||
|
||||
if (radio->stereo)
|
||||
amradio_set_stereo(radio, WANT_STEREO);
|
||||
else
|
||||
amradio_set_stereo(radio, WANT_MONO);
|
||||
|
||||
amradio_setfreq(radio, radio->curfreq);
|
||||
|
||||
if (!radio->muted)
|
||||
amradio_set_mute(radio, AMRADIO_START);
|
||||
|
||||
unlock:
|
||||
dev_info(&intf->dev, "coming out of suspend..\n");
|
||||
|
||||
mutex_unlock(&radio->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -623,7 +609,7 @@ static const struct v4l2_file_operations usb_amradio_fops = {
|
|||
.owner = THIS_MODULE,
|
||||
.open = usb_amradio_open,
|
||||
.release = usb_amradio_close,
|
||||
.ioctl = video_ioctl2,
|
||||
.ioctl = usb_amradio_ioctl,
|
||||
};
|
||||
|
||||
static const struct v4l2_ioctl_ops usb_amradio_ioctl_ops = {
|
||||
|
|
@ -643,10 +629,7 @@ static const struct v4l2_ioctl_ops usb_amradio_ioctl_ops = {
|
|||
|
||||
static void usb_amradio_video_device_release(struct video_device *videodev)
|
||||
{
|
||||
struct amradio_device *radio = video_get_drvdata(videodev);
|
||||
|
||||
/* we call v4l to free radio->videodev */
|
||||
video_device_release(videodev);
|
||||
struct amradio_device *radio = vdev_to_amradio(videodev);
|
||||
|
||||
v4l2_device_unregister(&radio->v4l2_dev);
|
||||
|
||||
|
|
@ -660,70 +643,63 @@ static int usb_amradio_probe(struct usb_interface *intf,
|
|||
const struct usb_device_id *id)
|
||||
{
|
||||
struct amradio_device *radio;
|
||||
struct v4l2_device *v4l2_dev;
|
||||
int retval;
|
||||
int retval = 0;
|
||||
|
||||
radio = kzalloc(sizeof(struct amradio_device), GFP_KERNEL);
|
||||
|
||||
if (!radio) {
|
||||
dev_err(&intf->dev, "kmalloc for amradio_device failed\n");
|
||||
return -ENOMEM;
|
||||
retval = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
radio->buffer = kmalloc(BUFFER_LENGTH, GFP_KERNEL);
|
||||
|
||||
if (!radio->buffer) {
|
||||
dev_err(&intf->dev, "kmalloc for radio->buffer failed\n");
|
||||
kfree(radio);
|
||||
return -ENOMEM;
|
||||
retval = -ENOMEM;
|
||||
goto err_nobuf;
|
||||
}
|
||||
|
||||
v4l2_dev = &radio->v4l2_dev;
|
||||
retval = v4l2_device_register(&intf->dev, v4l2_dev);
|
||||
retval = v4l2_device_register(&intf->dev, &radio->v4l2_dev);
|
||||
if (retval < 0) {
|
||||
dev_err(&intf->dev, "couldn't register v4l2_device\n");
|
||||
kfree(radio->buffer);
|
||||
kfree(radio);
|
||||
return retval;
|
||||
goto err_v4l2;
|
||||
}
|
||||
|
||||
radio->videodev = video_device_alloc();
|
||||
strlcpy(radio->videodev.name, radio->v4l2_dev.name,
|
||||
sizeof(radio->videodev.name));
|
||||
radio->videodev.v4l2_dev = &radio->v4l2_dev;
|
||||
radio->videodev.fops = &usb_amradio_fops;
|
||||
radio->videodev.ioctl_ops = &usb_amradio_ioctl_ops;
|
||||
radio->videodev.release = usb_amradio_video_device_release;
|
||||
|
||||
if (!radio->videodev) {
|
||||
dev_err(&intf->dev, "video_device_alloc failed\n");
|
||||
kfree(radio->buffer);
|
||||
kfree(radio);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
strlcpy(radio->videodev->name, v4l2_dev->name, sizeof(radio->videodev->name));
|
||||
radio->videodev->v4l2_dev = v4l2_dev;
|
||||
radio->videodev->fops = &usb_amradio_fops;
|
||||
radio->videodev->ioctl_ops = &usb_amradio_ioctl_ops;
|
||||
radio->videodev->release = usb_amradio_video_device_release;
|
||||
|
||||
radio->removed = 0;
|
||||
radio->users = 0;
|
||||
radio->usbdev = interface_to_usbdev(intf);
|
||||
radio->intf = intf;
|
||||
radio->curfreq = 95.16 * FREQ_MUL;
|
||||
radio->stereo = -1;
|
||||
|
||||
mutex_init(&radio->lock);
|
||||
|
||||
video_set_drvdata(radio->videodev, radio);
|
||||
video_set_drvdata(&radio->videodev, radio);
|
||||
|
||||
retval = video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr);
|
||||
retval = video_register_device(&radio->videodev, VFL_TYPE_RADIO,
|
||||
radio_nr);
|
||||
if (retval < 0) {
|
||||
dev_err(&intf->dev, "could not register video device\n");
|
||||
video_device_release(radio->videodev);
|
||||
v4l2_device_unregister(v4l2_dev);
|
||||
kfree(radio->buffer);
|
||||
kfree(radio);
|
||||
return -EIO;
|
||||
goto err_vdev;
|
||||
}
|
||||
|
||||
usb_set_intfdata(intf, radio);
|
||||
return 0;
|
||||
|
||||
err_vdev:
|
||||
v4l2_device_unregister(&radio->v4l2_dev);
|
||||
err_v4l2:
|
||||
kfree(radio->buffer);
|
||||
err_nobuf:
|
||||
kfree(radio);
|
||||
err:
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int __init amradio_init(void)
|
||||
|
|
|
|||
232
drivers/media/radio/tef6862.c
Normal file
232
drivers/media/radio/tef6862.c
Normal file
|
|
@ -0,0 +1,232 @@
|
|||
/*
|
||||
* tef6862.c Philips TEF6862 Car Radio Enhanced Selectivity Tuner
|
||||
* Copyright (c) 2009 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-id.h>
|
||||
#include <media/v4l2-ioctl.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <media/v4l2-chip-ident.h>
|
||||
|
||||
#define DRIVER_NAME "tef6862"
|
||||
|
||||
#define FREQ_MUL 16000
|
||||
|
||||
#define TEF6862_LO_FREQ (875 * FREQ_MUL / 10)
|
||||
#define TEF6862_HI_FREQ (108 * FREQ_MUL)
|
||||
|
||||
/* Write mode sub addresses */
|
||||
#define WM_SUB_BANDWIDTH 0x0
|
||||
#define WM_SUB_PLLM 0x1
|
||||
#define WM_SUB_PLLL 0x2
|
||||
#define WM_SUB_DAA 0x3
|
||||
#define WM_SUB_AGC 0x4
|
||||
#define WM_SUB_BAND 0x5
|
||||
#define WM_SUB_CONTROL 0x6
|
||||
#define WM_SUB_LEVEL 0x7
|
||||
#define WM_SUB_IFCF 0x8
|
||||
#define WM_SUB_IFCAP 0x9
|
||||
#define WM_SUB_ACD 0xA
|
||||
#define WM_SUB_TEST 0xF
|
||||
|
||||
/* Different modes of the MSA register */
|
||||
#define MODE_BUFFER 0x0
|
||||
#define MODE_PRESET 0x1
|
||||
#define MODE_SEARCH 0x2
|
||||
#define MODE_AF_UPDATE 0x3
|
||||
#define MODE_JUMP 0x4
|
||||
#define MODE_CHECK 0x5
|
||||
#define MODE_LOAD 0x6
|
||||
#define MODE_END 0x7
|
||||
#define MODE_SHIFT 5
|
||||
|
||||
struct tef6862_state {
|
||||
struct v4l2_subdev sd;
|
||||
unsigned long freq;
|
||||
};
|
||||
|
||||
static inline struct tef6862_state *to_state(struct v4l2_subdev *sd)
|
||||
{
|
||||
return container_of(sd, struct tef6862_state, sd);
|
||||
}
|
||||
|
||||
static u16 tef6862_sigstr(struct i2c_client *client)
|
||||
{
|
||||
u8 buf[4];
|
||||
int err = i2c_master_recv(client, buf, sizeof(buf));
|
||||
if (err == sizeof(buf))
|
||||
return buf[3] << 8;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tef6862_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *v)
|
||||
{
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
|
||||
/* only support FM for now */
|
||||
strlcpy(v->name, "FM", sizeof(v->name));
|
||||
v->type = V4L2_TUNER_RADIO;
|
||||
v->rangelow = TEF6862_LO_FREQ;
|
||||
v->rangehigh = TEF6862_HI_FREQ;
|
||||
v->rxsubchans = V4L2_TUNER_SUB_MONO;
|
||||
v->capability = V4L2_TUNER_CAP_LOW;
|
||||
v->audmode = V4L2_TUNER_MODE_STEREO;
|
||||
v->signal = tef6862_sigstr(v4l2_get_subdevdata(sd));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tef6862_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *v)
|
||||
{
|
||||
return v->index ? -EINVAL : 0;
|
||||
}
|
||||
|
||||
static int tef6862_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f)
|
||||
{
|
||||
struct tef6862_state *state = to_state(sd);
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
u16 pll;
|
||||
u8 i2cmsg[3];
|
||||
int err;
|
||||
|
||||
if (f->tuner != 0)
|
||||
return -EINVAL;
|
||||
|
||||
pll = 1964 + ((f->frequency - TEF6862_LO_FREQ) * 20) / FREQ_MUL;
|
||||
i2cmsg[0] = (MODE_PRESET << MODE_SHIFT) | WM_SUB_PLLM;
|
||||
i2cmsg[1] = (pll >> 8) & 0xff;
|
||||
i2cmsg[2] = pll & 0xff;
|
||||
|
||||
err = i2c_master_send(client, i2cmsg, sizeof(i2cmsg));
|
||||
if (!err)
|
||||
state->freq = f->frequency;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int tef6862_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f)
|
||||
{
|
||||
struct tef6862_state *state = to_state(sd);
|
||||
|
||||
if (f->tuner != 0)
|
||||
return -EINVAL;
|
||||
f->type = V4L2_TUNER_RADIO;
|
||||
f->frequency = state->freq;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tef6862_g_chip_ident(struct v4l2_subdev *sd,
|
||||
struct v4l2_dbg_chip_ident *chip)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
|
||||
return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TEF6862, 0);
|
||||
}
|
||||
|
||||
static const struct v4l2_subdev_tuner_ops tef6862_tuner_ops = {
|
||||
.g_tuner = tef6862_g_tuner,
|
||||
.s_tuner = tef6862_s_tuner,
|
||||
.s_frequency = tef6862_s_frequency,
|
||||
.g_frequency = tef6862_g_frequency,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_core_ops tef6862_core_ops = {
|
||||
.g_chip_ident = tef6862_g_chip_ident,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_ops tef6862_ops = {
|
||||
.core = &tef6862_core_ops,
|
||||
.tuner = &tef6862_tuner_ops,
|
||||
};
|
||||
|
||||
/*
|
||||
* Generic i2c probe
|
||||
* concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
|
||||
*/
|
||||
|
||||
static int __devinit tef6862_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct tef6862_state *state;
|
||||
struct v4l2_subdev *sd;
|
||||
|
||||
/* Check if the adapter supports the needed features */
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
return -EIO;
|
||||
|
||||
v4l_info(client, "chip found @ 0x%02x (%s)\n",
|
||||
client->addr << 1, client->adapter->name);
|
||||
|
||||
state = kmalloc(sizeof(struct tef6862_state), GFP_KERNEL);
|
||||
if (state == NULL)
|
||||
return -ENOMEM;
|
||||
state->freq = TEF6862_LO_FREQ;
|
||||
|
||||
sd = &state->sd;
|
||||
v4l2_i2c_subdev_init(sd, client, &tef6862_ops);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devexit tef6862_remove(struct i2c_client *client)
|
||||
{
|
||||
struct v4l2_subdev *sd = i2c_get_clientdata(client);
|
||||
|
||||
v4l2_device_unregister_subdev(sd);
|
||||
kfree(to_state(sd));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id tef6862_id[] = {
|
||||
{DRIVER_NAME, 0},
|
||||
{},
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(i2c, tef6862_id);
|
||||
|
||||
static struct i2c_driver tef6862_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = DRIVER_NAME,
|
||||
},
|
||||
.probe = tef6862_probe,
|
||||
.remove = tef6862_remove,
|
||||
.id_table = tef6862_id,
|
||||
};
|
||||
|
||||
static __init int tef6862_init(void)
|
||||
{
|
||||
return i2c_add_driver(&tef6862_driver);
|
||||
}
|
||||
|
||||
static __exit void tef6862_exit(void)
|
||||
{
|
||||
i2c_del_driver(&tef6862_driver);
|
||||
}
|
||||
|
||||
module_init(tef6862_init);
|
||||
module_exit(tef6862_exit);
|
||||
|
||||
MODULE_DESCRIPTION("TEF6862 Car Radio Enhanced Selectivity Tuner");
|
||||
MODULE_AUTHOR("Mocean Laboratories");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
|
|
@ -600,7 +600,7 @@ source "drivers/media/video/bt8xx/Kconfig"
|
|||
|
||||
config VIDEO_PMS
|
||||
tristate "Mediavision Pro Movie Studio Video For Linux"
|
||||
depends on ISA && VIDEO_V4L1
|
||||
depends on ISA && VIDEO_V4L2
|
||||
help
|
||||
Say Y if you have such a thing.
|
||||
|
||||
|
|
@ -847,6 +847,12 @@ config SOC_CAMERA_MT9V022
|
|||
help
|
||||
This driver supports MT9V022 cameras from Micron
|
||||
|
||||
config SOC_CAMERA_RJ54N1
|
||||
tristate "rj54n1cb0c support"
|
||||
depends on SOC_CAMERA && I2C
|
||||
help
|
||||
This is a rj54n1cb0c video driver
|
||||
|
||||
config SOC_CAMERA_TW9910
|
||||
tristate "tw9910 support"
|
||||
depends on SOC_CAMERA && I2C
|
||||
|
|
@ -865,6 +871,12 @@ config SOC_CAMERA_OV772X
|
|||
help
|
||||
This is a ov772x camera driver
|
||||
|
||||
config SOC_CAMERA_OV9640
|
||||
tristate "ov9640 camera support"
|
||||
depends on SOC_CAMERA && I2C
|
||||
help
|
||||
This is a ov9640 camera driver
|
||||
|
||||
config MX1_VIDEO
|
||||
bool
|
||||
|
||||
|
|
@ -939,9 +951,14 @@ source "drivers/media/video/usbvideo/Kconfig"
|
|||
source "drivers/media/video/et61x251/Kconfig"
|
||||
|
||||
config VIDEO_OVCAMCHIP
|
||||
tristate "OmniVision Camera Chip support"
|
||||
tristate "OmniVision Camera Chip support (DEPRECATED)"
|
||||
depends on I2C && VIDEO_V4L1
|
||||
---help---
|
||||
This driver is DEPRECATED please use the gspca ov519 module
|
||||
instead. Note that for the ov511 / ov518 support of the gspca module
|
||||
you need atleast version 0.6.0 of libv4l and for the w9968cf
|
||||
atleast version 0.6.3 of libv4l.
|
||||
|
||||
Support for the OmniVision OV6xxx and OV7xxx series of camera chips.
|
||||
This driver is intended to be used with the ov511 and w9968cf USB
|
||||
camera drivers.
|
||||
|
|
@ -950,9 +967,13 @@ config VIDEO_OVCAMCHIP
|
|||
module will be called ovcamchip.
|
||||
|
||||
config USB_W9968CF
|
||||
tristate "USB W996[87]CF JPEG Dual Mode Camera support"
|
||||
tristate "USB W996[87]CF JPEG Dual Mode Camera support (DEPRECATED)"
|
||||
depends on VIDEO_V4L1 && I2C && VIDEO_OVCAMCHIP
|
||||
---help---
|
||||
This driver is DEPRECATED please use the gspca ov519 module
|
||||
instead. Note that for the w9968cf support of the gspca module
|
||||
you need atleast version 0.6.3 of libv4l.
|
||||
|
||||
Say Y here if you want support for cameras based on OV681 or
|
||||
Winbond W9967CF/W9968CF JPEG USB Dual Mode Camera Chips.
|
||||
|
||||
|
|
@ -995,9 +1016,13 @@ config USB_SE401
|
|||
source "drivers/media/video/sn9c102/Kconfig"
|
||||
|
||||
config USB_STV680
|
||||
tristate "USB STV680 (Pencam) Camera support"
|
||||
tristate "USB STV680 (Pencam) Camera support (DEPRECATED)"
|
||||
depends on VIDEO_V4L1
|
||||
---help---
|
||||
This driver is DEPRECATED please use the gspca stv0680 module
|
||||
instead. Note that for the gspca stv0680 module you need
|
||||
atleast version 0.6.3 of libv4l.
|
||||
|
||||
Say Y here if you want to connect this type of camera to your
|
||||
computer's USB port. This includes the Pencam line of cameras.
|
||||
See <file:Documentation/video4linux/stv680.txt> for more information
|
||||
|
|
|
|||
|
|
@ -77,6 +77,8 @@ obj-$(CONFIG_SOC_CAMERA_MT9M111) += mt9m111.o
|
|||
obj-$(CONFIG_SOC_CAMERA_MT9T031) += mt9t031.o
|
||||
obj-$(CONFIG_SOC_CAMERA_MT9V022) += mt9v022.o
|
||||
obj-$(CONFIG_SOC_CAMERA_OV772X) += ov772x.o
|
||||
obj-$(CONFIG_SOC_CAMERA_OV9640) += ov9640.o
|
||||
obj-$(CONFIG_SOC_CAMERA_RJ54N1) += rj54n1cb0c.o
|
||||
obj-$(CONFIG_SOC_CAMERA_TW9910) += tw9910.o
|
||||
|
||||
# And now the v4l2 drivers:
|
||||
|
|
|
|||
|
|
@ -27,17 +27,40 @@
|
|||
#include <linux/videodev2.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <media/v4l2-chip-ident.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#define DRIVER_NAME "adv7180"
|
||||
|
||||
#define ADV7180_INPUT_CONTROL_REG 0x00
|
||||
#define ADV7180_INPUT_CONTROL_PAL_BG_NTSC_J_SECAM 0x00
|
||||
#define ADV7180_AUTODETECT_ENABLE_REG 0x07
|
||||
#define ADV7180_AUTODETECT_DEFAULT 0x7f
|
||||
#define ADV7180_INPUT_CONTROL_REG 0x00
|
||||
#define ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM 0x00
|
||||
#define ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM_PED 0x10
|
||||
#define ADV7180_INPUT_CONTROL_AD_PAL_N_NTSC_J_SECAM 0x20
|
||||
#define ADV7180_INPUT_CONTROL_AD_PAL_N_NTSC_M_SECAM 0x30
|
||||
#define ADV7180_INPUT_CONTROL_NTSC_J 0x40
|
||||
#define ADV7180_INPUT_CONTROL_NTSC_M 0x50
|
||||
#define ADV7180_INPUT_CONTROL_PAL60 0x60
|
||||
#define ADV7180_INPUT_CONTROL_NTSC_443 0x70
|
||||
#define ADV7180_INPUT_CONTROL_PAL_BG 0x80
|
||||
#define ADV7180_INPUT_CONTROL_PAL_N 0x90
|
||||
#define ADV7180_INPUT_CONTROL_PAL_M 0xa0
|
||||
#define ADV7180_INPUT_CONTROL_PAL_M_PED 0xb0
|
||||
#define ADV7180_INPUT_CONTROL_PAL_COMB_N 0xc0
|
||||
#define ADV7180_INPUT_CONTROL_PAL_COMB_N_PED 0xd0
|
||||
#define ADV7180_INPUT_CONTROL_PAL_SECAM 0xe0
|
||||
#define ADV7180_INPUT_CONTROL_PAL_SECAM_PED 0xf0
|
||||
|
||||
#define ADV7180_EXTENDED_OUTPUT_CONTROL_REG 0x04
|
||||
#define ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS 0xC5
|
||||
|
||||
#define ADV7180_STATUS1_REG 0x10
|
||||
#define ADV7180_STATUS1_AUTOD_MASK 0x70
|
||||
#define ADV7180_AUTODETECT_ENABLE_REG 0x07
|
||||
#define ADV7180_AUTODETECT_DEFAULT 0x7f
|
||||
|
||||
#define ADV7180_ADI_CTRL_REG 0x0e
|
||||
#define ADV7180_ADI_CTRL_IRQ_SPACE 0x20
|
||||
|
||||
#define ADV7180_STATUS1_REG 0x10
|
||||
#define ADV7180_STATUS1_IN_LOCK 0x01
|
||||
#define ADV7180_STATUS1_AUTOD_MASK 0x70
|
||||
#define ADV7180_STATUS1_AUTOD_NTSM_M_J 0x00
|
||||
#define ADV7180_STATUS1_AUTOD_NTSC_4_43 0x10
|
||||
#define ADV7180_STATUS1_AUTOD_PAL_M 0x20
|
||||
|
|
@ -50,18 +73,37 @@
|
|||
#define ADV7180_IDENT_REG 0x11
|
||||
#define ADV7180_ID_7180 0x18
|
||||
|
||||
#define ADV7180_ICONF1_ADI 0x40
|
||||
#define ADV7180_ICONF1_ACTIVE_LOW 0x01
|
||||
#define ADV7180_ICONF1_PSYNC_ONLY 0x10
|
||||
#define ADV7180_ICONF1_ACTIVE_TO_CLR 0xC0
|
||||
|
||||
#define ADV7180_IRQ1_LOCK 0x01
|
||||
#define ADV7180_IRQ1_UNLOCK 0x02
|
||||
#define ADV7180_ISR1_ADI 0x42
|
||||
#define ADV7180_ICR1_ADI 0x43
|
||||
#define ADV7180_IMR1_ADI 0x44
|
||||
#define ADV7180_IMR2_ADI 0x48
|
||||
#define ADV7180_IRQ3_AD_CHANGE 0x08
|
||||
#define ADV7180_ISR3_ADI 0x4A
|
||||
#define ADV7180_ICR3_ADI 0x4B
|
||||
#define ADV7180_IMR3_ADI 0x4C
|
||||
#define ADV7180_IMR4_ADI 0x50
|
||||
|
||||
struct adv7180_state {
|
||||
struct v4l2_subdev sd;
|
||||
struct v4l2_subdev sd;
|
||||
struct work_struct work;
|
||||
struct mutex mutex; /* mutual excl. when accessing chip */
|
||||
int irq;
|
||||
v4l2_std_id curr_norm;
|
||||
bool autodetect;
|
||||
};
|
||||
|
||||
static v4l2_std_id determine_norm(struct i2c_client *client)
|
||||
static v4l2_std_id adv7180_std_to_v4l2(u8 status1)
|
||||
{
|
||||
u8 status1 = i2c_smbus_read_byte_data(client, ADV7180_STATUS1_REG);
|
||||
|
||||
switch (status1 & ADV7180_STATUS1_AUTOD_MASK) {
|
||||
case ADV7180_STATUS1_AUTOD_NTSM_M_J:
|
||||
return V4L2_STD_NTSC_M_JP;
|
||||
return V4L2_STD_NTSC;
|
||||
case ADV7180_STATUS1_AUTOD_NTSC_4_43:
|
||||
return V4L2_STD_NTSC_443;
|
||||
case ADV7180_STATUS1_AUTOD_PAL_M:
|
||||
|
|
@ -81,6 +123,53 @@ static v4l2_std_id determine_norm(struct i2c_client *client)
|
|||
}
|
||||
}
|
||||
|
||||
static int v4l2_std_to_adv7180(v4l2_std_id std)
|
||||
{
|
||||
if (std == V4L2_STD_PAL_60)
|
||||
return ADV7180_INPUT_CONTROL_PAL60;
|
||||
if (std == V4L2_STD_NTSC_443)
|
||||
return ADV7180_INPUT_CONTROL_NTSC_443;
|
||||
if (std == V4L2_STD_PAL_N)
|
||||
return ADV7180_INPUT_CONTROL_PAL_N;
|
||||
if (std == V4L2_STD_PAL_M)
|
||||
return ADV7180_INPUT_CONTROL_PAL_M;
|
||||
if (std == V4L2_STD_PAL_Nc)
|
||||
return ADV7180_INPUT_CONTROL_PAL_COMB_N;
|
||||
|
||||
if (std & V4L2_STD_PAL)
|
||||
return ADV7180_INPUT_CONTROL_PAL_BG;
|
||||
if (std & V4L2_STD_NTSC)
|
||||
return ADV7180_INPUT_CONTROL_NTSC_M;
|
||||
if (std & V4L2_STD_SECAM)
|
||||
return ADV7180_INPUT_CONTROL_PAL_SECAM;
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static u32 adv7180_status_to_v4l2(u8 status1)
|
||||
{
|
||||
if (!(status1 & ADV7180_STATUS1_IN_LOCK))
|
||||
return V4L2_IN_ST_NO_SIGNAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __adv7180_status(struct i2c_client *client, u32 *status,
|
||||
v4l2_std_id *std)
|
||||
{
|
||||
int status1 = i2c_smbus_read_byte_data(client, ADV7180_STATUS1_REG);
|
||||
|
||||
if (status1 < 0)
|
||||
return status1;
|
||||
|
||||
if (status)
|
||||
*status = adv7180_status_to_v4l2(status1);
|
||||
if (std)
|
||||
*std = adv7180_std_to_v4l2(status1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline struct adv7180_state *to_state(struct v4l2_subdev *sd)
|
||||
{
|
||||
return container_of(sd, struct adv7180_state, sd);
|
||||
|
|
@ -88,10 +177,31 @@ static inline struct adv7180_state *to_state(struct v4l2_subdev *sd)
|
|||
|
||||
static int adv7180_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
struct adv7180_state *state = to_state(sd);
|
||||
int err = mutex_lock_interruptible(&state->mutex);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
*std = determine_norm(client);
|
||||
return 0;
|
||||
/* when we are interrupt driven we know the state */
|
||||
if (!state->autodetect || state->irq > 0)
|
||||
*std = state->curr_norm;
|
||||
else
|
||||
err = __adv7180_status(v4l2_get_subdevdata(sd), NULL, std);
|
||||
|
||||
mutex_unlock(&state->mutex);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int adv7180_g_input_status(struct v4l2_subdev *sd, u32 *status)
|
||||
{
|
||||
struct adv7180_state *state = to_state(sd);
|
||||
int ret = mutex_lock_interruptible(&state->mutex);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = __adv7180_status(v4l2_get_subdevdata(sd), status, NULL);
|
||||
mutex_unlock(&state->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int adv7180_g_chip_ident(struct v4l2_subdev *sd,
|
||||
|
|
@ -102,12 +212,51 @@ static int adv7180_g_chip_ident(struct v4l2_subdev *sd,
|
|||
return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7180, 0);
|
||||
}
|
||||
|
||||
static int adv7180_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
|
||||
{
|
||||
struct adv7180_state *state = to_state(sd);
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
int ret = mutex_lock_interruptible(&state->mutex);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* all standards -> autodetect */
|
||||
if (std == V4L2_STD_ALL) {
|
||||
ret = i2c_smbus_write_byte_data(client,
|
||||
ADV7180_INPUT_CONTROL_REG,
|
||||
ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
__adv7180_status(client, NULL, &state->curr_norm);
|
||||
state->autodetect = true;
|
||||
} else {
|
||||
ret = v4l2_std_to_adv7180(std);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(client,
|
||||
ADV7180_INPUT_CONTROL_REG, ret);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
state->curr_norm = std;
|
||||
state->autodetect = false;
|
||||
}
|
||||
ret = 0;
|
||||
out:
|
||||
mutex_unlock(&state->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct v4l2_subdev_video_ops adv7180_video_ops = {
|
||||
.querystd = adv7180_querystd,
|
||||
.g_input_status = adv7180_g_input_status,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_core_ops adv7180_core_ops = {
|
||||
.g_chip_ident = adv7180_g_chip_ident,
|
||||
.s_std = adv7180_s_std,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_ops adv7180_ops = {
|
||||
|
|
@ -115,12 +264,45 @@ static const struct v4l2_subdev_ops adv7180_ops = {
|
|||
.video = &adv7180_video_ops,
|
||||
};
|
||||
|
||||
static void adv7180_work(struct work_struct *work)
|
||||
{
|
||||
struct adv7180_state *state = container_of(work, struct adv7180_state,
|
||||
work);
|
||||
struct i2c_client *client = v4l2_get_subdevdata(&state->sd);
|
||||
u8 isr3;
|
||||
|
||||
mutex_lock(&state->mutex);
|
||||
i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG,
|
||||
ADV7180_ADI_CTRL_IRQ_SPACE);
|
||||
isr3 = i2c_smbus_read_byte_data(client, ADV7180_ISR3_ADI);
|
||||
/* clear */
|
||||
i2c_smbus_write_byte_data(client, ADV7180_ICR3_ADI, isr3);
|
||||
i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG, 0);
|
||||
|
||||
if (isr3 & ADV7180_IRQ3_AD_CHANGE && state->autodetect)
|
||||
__adv7180_status(client, NULL, &state->curr_norm);
|
||||
mutex_unlock(&state->mutex);
|
||||
|
||||
enable_irq(state->irq);
|
||||
}
|
||||
|
||||
static irqreturn_t adv7180_irq(int irq, void *devid)
|
||||
{
|
||||
struct adv7180_state *state = devid;
|
||||
|
||||
schedule_work(&state->work);
|
||||
|
||||
disable_irq_nosync(state->irq);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generic i2c probe
|
||||
* concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
|
||||
*/
|
||||
|
||||
static int adv7180_probe(struct i2c_client *client,
|
||||
static __devinit int adv7180_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct adv7180_state *state;
|
||||
|
|
@ -135,32 +317,111 @@ static int adv7180_probe(struct i2c_client *client,
|
|||
client->addr << 1, client->adapter->name);
|
||||
|
||||
state = kzalloc(sizeof(struct adv7180_state), GFP_KERNEL);
|
||||
if (state == NULL)
|
||||
return -ENOMEM;
|
||||
if (state == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
state->irq = client->irq;
|
||||
INIT_WORK(&state->work, adv7180_work);
|
||||
mutex_init(&state->mutex);
|
||||
state->autodetect = true;
|
||||
sd = &state->sd;
|
||||
v4l2_i2c_subdev_init(sd, client, &adv7180_ops);
|
||||
|
||||
/* Initialize adv7180 */
|
||||
/* enable autodetection */
|
||||
/* Enable autodetection */
|
||||
ret = i2c_smbus_write_byte_data(client, ADV7180_INPUT_CONTROL_REG,
|
||||
ADV7180_INPUT_CONTROL_PAL_BG_NTSC_J_SECAM);
|
||||
if (ret > 0)
|
||||
ret = i2c_smbus_write_byte_data(client,
|
||||
ADV7180_AUTODETECT_ENABLE_REG,
|
||||
ADV7180_AUTODETECT_DEFAULT);
|
||||
if (ret < 0) {
|
||||
printk(KERN_ERR DRIVER_NAME
|
||||
": Failed to communicate to chip: %d\n", ret);
|
||||
return ret;
|
||||
ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM);
|
||||
if (ret < 0)
|
||||
goto err_unreg_subdev;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(client, ADV7180_AUTODETECT_ENABLE_REG,
|
||||
ADV7180_AUTODETECT_DEFAULT);
|
||||
if (ret < 0)
|
||||
goto err_unreg_subdev;
|
||||
|
||||
/* ITU-R BT.656-4 compatible */
|
||||
ret = i2c_smbus_write_byte_data(client,
|
||||
ADV7180_EXTENDED_OUTPUT_CONTROL_REG,
|
||||
ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS);
|
||||
if (ret < 0)
|
||||
goto err_unreg_subdev;
|
||||
|
||||
/* read current norm */
|
||||
__adv7180_status(client, NULL, &state->curr_norm);
|
||||
|
||||
/* register for interrupts */
|
||||
if (state->irq > 0) {
|
||||
ret = request_irq(state->irq, adv7180_irq, 0, DRIVER_NAME,
|
||||
state);
|
||||
if (ret)
|
||||
goto err_unreg_subdev;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG,
|
||||
ADV7180_ADI_CTRL_IRQ_SPACE);
|
||||
if (ret < 0)
|
||||
goto err_unreg_subdev;
|
||||
|
||||
/* config the Interrupt pin to be active low */
|
||||
ret = i2c_smbus_write_byte_data(client, ADV7180_ICONF1_ADI,
|
||||
ADV7180_ICONF1_ACTIVE_LOW | ADV7180_ICONF1_PSYNC_ONLY);
|
||||
if (ret < 0)
|
||||
goto err_unreg_subdev;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(client, ADV7180_IMR1_ADI, 0);
|
||||
if (ret < 0)
|
||||
goto err_unreg_subdev;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(client, ADV7180_IMR2_ADI, 0);
|
||||
if (ret < 0)
|
||||
goto err_unreg_subdev;
|
||||
|
||||
/* enable AD change interrupts interrupts */
|
||||
ret = i2c_smbus_write_byte_data(client, ADV7180_IMR3_ADI,
|
||||
ADV7180_IRQ3_AD_CHANGE);
|
||||
if (ret < 0)
|
||||
goto err_unreg_subdev;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(client, ADV7180_IMR4_ADI, 0);
|
||||
if (ret < 0)
|
||||
goto err_unreg_subdev;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG,
|
||||
0);
|
||||
if (ret < 0)
|
||||
goto err_unreg_subdev;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_unreg_subdev:
|
||||
mutex_destroy(&state->mutex);
|
||||
v4l2_device_unregister_subdev(sd);
|
||||
kfree(state);
|
||||
err:
|
||||
printk(KERN_ERR DRIVER_NAME ": Failed to probe: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int adv7180_remove(struct i2c_client *client)
|
||||
static __devexit int adv7180_remove(struct i2c_client *client)
|
||||
{
|
||||
struct v4l2_subdev *sd = i2c_get_clientdata(client);
|
||||
struct adv7180_state *state = to_state(sd);
|
||||
|
||||
if (state->irq > 0) {
|
||||
free_irq(client->irq, state);
|
||||
if (cancel_work_sync(&state->work)) {
|
||||
/*
|
||||
* Work was pending, therefore we need to enable
|
||||
* IRQ here to balance the disable_irq() done in the
|
||||
* interrupt handler.
|
||||
*/
|
||||
enable_irq(state->irq);
|
||||
}
|
||||
}
|
||||
|
||||
mutex_destroy(&state->mutex);
|
||||
v4l2_device_unregister_subdev(sd);
|
||||
kfree(to_state(sd));
|
||||
return 0;
|
||||
|
|
@ -179,7 +440,7 @@ static struct i2c_driver adv7180_driver = {
|
|||
.name = DRIVER_NAME,
|
||||
},
|
||||
.probe = adv7180_probe,
|
||||
.remove = adv7180_remove,
|
||||
.remove = __devexit_p(adv7180_remove),
|
||||
.id_table = adv7180_id,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -830,7 +830,7 @@ static int au0828_v4l2_close(struct file *filp)
|
|||
au0828_uninit_isoc(dev);
|
||||
|
||||
/* Save some power by putting tuner to sleep */
|
||||
v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_standby);
|
||||
v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
|
||||
|
||||
/* When close the device, set the usb intf0 into alt0 to free
|
||||
USB bandwidth */
|
||||
|
|
|
|||
|
|
@ -299,7 +299,7 @@ static int bt819_s_routing(struct v4l2_subdev *sd,
|
|||
|
||||
v4l2_dbg(1, debug, sd, "set input %x\n", input);
|
||||
|
||||
if (input < 0 || input > 7)
|
||||
if (input > 7)
|
||||
return -EINVAL;
|
||||
|
||||
if (sd->v4l2_dev == NULL || sd->v4l2_dev->notify == NULL)
|
||||
|
|
|
|||
|
|
@ -73,12 +73,12 @@ static void ir_handle_key(struct bttv *btv)
|
|||
|
||||
if ((ir->mask_keydown && (0 != (gpio & ir->mask_keydown))) ||
|
||||
(ir->mask_keyup && (0 == (gpio & ir->mask_keyup)))) {
|
||||
ir_input_keydown(ir->dev,&ir->ir,data,data);
|
||||
ir_input_keydown(ir->dev, &ir->ir, data);
|
||||
} else {
|
||||
/* HACK: Probably, ir->mask_keydown is missing
|
||||
for this board */
|
||||
if (btv->c.type == BTTV_BOARD_WINFAST2000)
|
||||
ir_input_keydown(ir->dev, &ir->ir, data, data);
|
||||
ir_input_keydown(ir->dev, &ir->ir, data);
|
||||
|
||||
ir_input_nokey(ir->dev,&ir->ir);
|
||||
}
|
||||
|
|
@ -104,7 +104,7 @@ static void ir_enltv_handle_key(struct bttv *btv)
|
|||
gpio, data,
|
||||
(gpio & ir->mask_keyup) ? " up" : "up/down");
|
||||
|
||||
ir_input_keydown(ir->dev, &ir->ir, data, data);
|
||||
ir_input_keydown(ir->dev, &ir->ir, data);
|
||||
if (keyup)
|
||||
ir_input_nokey(ir->dev, &ir->ir);
|
||||
} else {
|
||||
|
|
@ -118,7 +118,7 @@ static void ir_enltv_handle_key(struct bttv *btv)
|
|||
if (keyup)
|
||||
ir_input_nokey(ir->dev, &ir->ir);
|
||||
else
|
||||
ir_input_keydown(ir->dev, &ir->ir, data, data);
|
||||
ir_input_keydown(ir->dev, &ir->ir, data);
|
||||
}
|
||||
|
||||
ir->last_gpio = data | keyup;
|
||||
|
|
@ -368,7 +368,10 @@ int bttv_input_init(struct bttv *btv)
|
|||
snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0",
|
||||
pci_name(btv->c.pci));
|
||||
|
||||
ir_input_init(input_dev, &ir->ir, ir_type, ir_codes);
|
||||
err = ir_input_init(input_dev, &ir->ir, ir_type, ir_codes);
|
||||
if (err < 0)
|
||||
goto err_out_free;
|
||||
|
||||
input_dev->name = ir->name;
|
||||
input_dev->phys = ir->phys;
|
||||
input_dev->id.bustype = BUS_PCI;
|
||||
|
|
@ -400,6 +403,7 @@ int bttv_input_init(struct bttv *btv)
|
|||
bttv_ir_stop(btv);
|
||||
btv->remote = NULL;
|
||||
err_out_free:
|
||||
ir_input_free(input_dev);
|
||||
input_free_device(input_dev);
|
||||
kfree(ir);
|
||||
return err;
|
||||
|
|
@ -411,6 +415,7 @@ void bttv_input_fini(struct bttv *btv)
|
|||
return;
|
||||
|
||||
bttv_ir_stop(btv);
|
||||
ir_input_free(btv->remote->dev);
|
||||
input_unregister_device(btv->remote->dev);
|
||||
kfree(btv->remote);
|
||||
btv->remote = NULL;
|
||||
|
|
|
|||
|
|
@ -99,10 +99,8 @@ int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 and_mask,
|
|||
or_value);
|
||||
}
|
||||
|
||||
static int cx18_av_init(struct v4l2_subdev *sd, u32 val)
|
||||
static void cx18_av_init(struct cx18 *cx)
|
||||
{
|
||||
struct cx18 *cx = v4l2_get_subdevdata(sd);
|
||||
|
||||
/*
|
||||
* The crystal freq used in calculations in this driver will be
|
||||
* 28.636360 MHz.
|
||||
|
|
@ -125,7 +123,6 @@ static int cx18_av_init(struct v4l2_subdev *sd, u32 val)
|
|||
|
||||
/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x16 */
|
||||
cx18_av_write(cx, CXADEC_I2S_MCLK, 0x56);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cx18_av_initialize(struct v4l2_subdev *sd)
|
||||
|
|
@ -198,7 +195,7 @@ static void cx18_av_initialize(struct v4l2_subdev *sd)
|
|||
cx18_av_and_or4(cx, CXADEC_CHIP_CTRL, 0xFFFBFFFF, 0x00120000);
|
||||
|
||||
/* Setup the Video and and Aux/Audio PLLs */
|
||||
cx18_av_init(sd, 0);
|
||||
cx18_av_init(cx);
|
||||
|
||||
/* set video to auto-detect */
|
||||
/* Clear bits 11-12 to enable slow locking mode. Set autodetect mode */
|
||||
|
|
@ -1355,7 +1352,6 @@ static int cx18_av_s_register(struct v4l2_subdev *sd,
|
|||
static const struct v4l2_subdev_core_ops cx18_av_general_ops = {
|
||||
.g_chip_ident = cx18_av_g_chip_ident,
|
||||
.log_status = cx18_av_log_status,
|
||||
.init = cx18_av_init,
|
||||
.load_fw = cx18_av_load_fw,
|
||||
.reset = cx18_av_reset,
|
||||
.queryctrl = cx18_av_queryctrl,
|
||||
|
|
@ -1399,6 +1395,7 @@ int cx18_av_probe(struct cx18 *cx)
|
|||
{
|
||||
struct cx18_av_state *state = &cx->av_state;
|
||||
struct v4l2_subdev *sd;
|
||||
int err;
|
||||
|
||||
state->rev = cx18_av_read4(cx, CXADEC_CHIP_CTRL) & 0xffff;
|
||||
state->id = ((state->rev >> 4) == CXADEC_CHIP_TYPE_MAKO)
|
||||
|
|
@ -1417,5 +1414,8 @@ int cx18_av_probe(struct cx18 *cx)
|
|||
snprintf(sd->name, sizeof(sd->name),
|
||||
"%s %03x", cx->v4l2_dev.name, (state->rev >> 4));
|
||||
sd->grp_id = CX18_HW_418_AV;
|
||||
return v4l2_device_register_subdev(&cx->v4l2_dev, sd);
|
||||
err = v4l2_device_register_subdev(&cx->v4l2_dev, sd);
|
||||
if (!err)
|
||||
cx18_av_init(cx);
|
||||
return err;
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue