diff options
Diffstat (limited to 'drivers/media/dvb')
75 files changed, 2316 insertions, 492 deletions
diff --git a/drivers/media/dvb/b2c2/Kconfig b/drivers/media/dvb/b2c2/Kconfig index d7417eac2aba..2583a865a58e 100644 --- a/drivers/media/dvb/b2c2/Kconfig +++ b/drivers/media/dvb/b2c2/Kconfig @@ -7,6 +7,7 @@ config DVB_B2C2_FLEXCOP select DVB_NXT2002 select DVB_STV0297 select DVB_BCM3510 + select DVB_LGDT330X help Support for the digital TV receiver chip made by B2C2 Inc. included in Technisats PCI cards and USB boxes. diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c index 47e28b0ee951..a35330315f65 100644 --- a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c +++ b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c @@ -13,6 +13,8 @@ #include "bcm3510.h" #include "stv0297.h" #include "mt312.h" +#include "lgdt330x.h" +#include "dvb-pll.h" /* lnb control */ @@ -234,7 +236,6 @@ static struct stv0299_config samsung_tbmu24112_config = { .inittab = samsung_tbmu24112_inittab, .mclk = 88000000UL, .invert = 0, - .enhanced_tuning = 0, .skip_reinit = 0, .lock_output = STV0229_LOCKOUTPUT_LK, .volt13_op0_op1 = STV0299_VOLT13_OP1, @@ -296,6 +297,52 @@ static int flexcop_fe_request_firmware(struct dvb_frontend* fe, const struct fir return request_firmware(fw, name, fc->dev); } +static int lgdt3303_pll_set(struct dvb_frontend* fe, + struct dvb_frontend_parameters* params) +{ + struct flexcop_device *fc = fe->dvb->priv; + u8 buf[4]; + struct i2c_msg msg = + { .addr = 0x61, .flags = 0, .buf = buf, .len = 4 }; + int err; + + dvb_pll_configure(&dvb_pll_tdvs_tua6034,buf, params->frequency, 0); + dprintk(1, "%s: tuner at 0x%02x bytes: 0x%02x 0x%02x 0x%02x 0x%02x\n", + __FUNCTION__, msg.addr, buf[0],buf[1],buf[2],buf[3]); + if ((err = i2c_transfer(&fc->i2c_adap, &msg, 1)) != 1) { + printk(KERN_WARNING "lgdt3303: %s error " + "(addr %02x <- %02x, err = %i)\n", + __FUNCTION__, buf[0], buf[1], err); + if (err < 0) + return err; + else + return -EREMOTEIO; + } + + buf[0] = 0x86 | 0x18; + buf[1] = 0x50; + msg.len = 2; + if ((err = i2c_transfer(&fc->i2c_adap, &msg, 1)) != 1) { + printk(KERN_WARNING "lgdt3303: %s error " + "(addr %02x <- %02x, err = %i)\n", + __FUNCTION__, buf[0], buf[1], err); + if (err < 0) + return err; + else + return -EREMOTEIO; + } + + return 0; +} + +static struct lgdt330x_config air2pc_atsc_hd5000_config = { + .demod_address = 0x59, + .demod_chip = LGDT3303, + .serial_mpeg = 0x04, + .pll_set = lgdt3303_pll_set, + .clock_polarity_flip = 1, +}; + static struct nxt2002_config samsung_tbmv_config = { .demod_address = 0x0a, .request_firmware = flexcop_fe_request_firmware, @@ -458,6 +505,11 @@ int flexcop_frontend_init(struct flexcop_device *fc) fc->dev_type = FC_AIR_ATSC2; info("found the nxt2002 at i2c address: 0x%02x",samsung_tbmv_config.demod_address); } else + /* try the air atsc 3nd generation (lgdt3303) */ + if ((fc->fe = lgdt330x_attach(&air2pc_atsc_hd5000_config, &fc->i2c_adap)) != NULL) { + fc->dev_type = FC_AIR_ATSC3; + info("found the lgdt3303 at i2c address: 0x%02x",air2pc_atsc_hd5000_config.demod_address); + } else /* try the air atsc 1nd generation (bcm3510)/panasonic ct10s */ if ((fc->fe = bcm3510_attach(&air2pc_atsc_first_gen_config, &fc->i2c_adap)) != NULL) { fc->dev_type = FC_AIR_ATSC1; diff --git a/drivers/media/dvb/b2c2/flexcop-hw-filter.c b/drivers/media/dvb/b2c2/flexcop-hw-filter.c index 75cf237196eb..b386cc66c6b3 100644 --- a/drivers/media/dvb/b2c2/flexcop-hw-filter.c +++ b/drivers/media/dvb/b2c2/flexcop-hw-filter.c @@ -19,7 +19,7 @@ void flexcop_smc_ctrl(struct flexcop_device *fc, int onoff) flexcop_set_ibi_value(ctrl_208,SMC_Enable_sig,onoff); } -void flexcop_null_filter_ctrl(struct flexcop_device *fc, int onoff) +static void flexcop_null_filter_ctrl(struct flexcop_device *fc, int onoff) { flexcop_set_ibi_value(ctrl_208,Null_filter_sig,onoff); } diff --git a/drivers/media/dvb/b2c2/flexcop-misc.c b/drivers/media/dvb/b2c2/flexcop-misc.c index 3a08d38b318a..62282d8dbfa8 100644 --- a/drivers/media/dvb/b2c2/flexcop-misc.c +++ b/drivers/media/dvb/b2c2/flexcop-misc.c @@ -51,6 +51,7 @@ const char *flexcop_device_names[] = { "Sky2PC/SkyStar 2 DVB-S", "Sky2PC/SkyStar 2 DVB-S (old version)", "Cable2PC/CableStar 2 DVB-C", + "Air2PC/AirStar 2 ATSC 3rd generation (HD5000)", }; const char *flexcop_bus_names[] = { diff --git a/drivers/media/dvb/b2c2/flexcop-reg.h b/drivers/media/dvb/b2c2/flexcop-reg.h index 4ae1eb5bfe98..23cc6431e2b8 100644 --- a/drivers/media/dvb/b2c2/flexcop-reg.h +++ b/drivers/media/dvb/b2c2/flexcop-reg.h @@ -26,6 +26,7 @@ typedef enum { FC_SKY, FC_SKY_OLD, FC_CABLE, + FC_AIR_ATSC3, } flexcop_device_type_t; typedef enum { diff --git a/drivers/media/dvb/b2c2/flexcop.c b/drivers/media/dvb/b2c2/flexcop.c index 12873d435406..123ed96f6faa 100644 --- a/drivers/media/dvb/b2c2/flexcop.c +++ b/drivers/media/dvb/b2c2/flexcop.c @@ -193,6 +193,7 @@ static void flexcop_reset(struct flexcop_device *fc) v204 = fc->read_ibi_reg(fc,misc_204); v204.misc_204.Per_reset_sig = 0; fc->write_ibi_reg(fc,misc_204,v204); + msleep(1); v204.misc_204.Per_reset_sig = 1; fc->write_ibi_reg(fc,misc_204,v204); } diff --git a/drivers/media/dvb/bt8xx/Kconfig b/drivers/media/dvb/bt8xx/Kconfig index 1e85d16491b0..2337b41714e0 100644 --- a/drivers/media/dvb/bt8xx/Kconfig +++ b/drivers/media/dvb/bt8xx/Kconfig @@ -6,10 +6,12 @@ config DVB_BT8XX select DVB_NXT6000 select DVB_CX24110 select DVB_OR51211 + select DVB_LGDT330X help Support for PCI cards based on the Bt8xx PCI bridge. Examples are the Nebula cards, the Pinnacle PCTV cards, the Twinhan DST cards, - the pcHDTV HD2000 cards, and certain AVerMedia cards. + the pcHDTV HD2000 cards, the DViCO FusionHDTV Lite cards, and + some AVerMedia cards. Since these cards have no MPEG decoder onboard, they transmit only compressed MPEG data over the PCI bus, so you need diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c index 34a837a1abf4..8977c7a313df 100644 --- a/drivers/media/dvb/bt8xx/dst.c +++ b/drivers/media/dvb/bt8xx/dst.c @@ -690,8 +690,8 @@ struct dst_types dst_tlist[] = { .device_id = "DTT-CI", .offset = 1, .dst_type = DST_TYPE_IS_TERR, - .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_FW_2, - .dst_feature = 0 + .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_MULTI_FE, + .dst_feature = DST_TYPE_HAS_CA }, { @@ -796,6 +796,56 @@ static int dst_get_vendor(struct dst_state *state) return 0; } +static int dst_get_tuner_info(struct dst_state *state) +{ + u8 get_tuner_1[] = { 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + u8 get_tuner_2[] = { 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + get_tuner_1[7] = dst_check_sum(get_tuner_1, 7); + get_tuner_2[7] = dst_check_sum(get_tuner_2, 7); + if (state->type_flags & DST_TYPE_HAS_MULTI_FE) { + if (dst_command(state, get_tuner_2, 8) < 0) { + dprintk(verbose, DST_INFO, 1, "Unsupported Command"); + return -1; + } + } else { + if (dst_command(state, get_tuner_1, 8) < 0) { + dprintk(verbose, DST_INFO, 1, "Unsupported Command"); + return -1; + } + } + memset(&state->board_info, '\0', 8); + memcpy(&state->board_info, &state->rxbuffer, 8); + if (state->type_flags & DST_TYPE_HAS_MULTI_FE) { + if (state->board_info[1] == 0x0b) { + if (state->type_flags & DST_TYPE_HAS_TS204) + state->type_flags &= ~DST_TYPE_HAS_TS204; + state->type_flags |= DST_TYPE_HAS_NEWTUNE; + dprintk(verbose, DST_INFO, 1, "DST type has TS=188"); + } else { + if (state->type_flags & DST_TYPE_HAS_NEWTUNE) + state->type_flags &= ~DST_TYPE_HAS_NEWTUNE; + state->type_flags |= DST_TYPE_HAS_TS204; + dprintk(verbose, DST_INFO, 1, "DST type has TS=204"); + } + } else { + if (state->board_info[0] == 0xbc) { + if (state->type_flags & DST_TYPE_HAS_TS204) + state->type_flags &= ~DST_TYPE_HAS_TS204; + state->type_flags |= DST_TYPE_HAS_NEWTUNE; + dprintk(verbose, DST_INFO, 1, "DST type has TS=188, Daughterboard=[%d]", state->board_info[1]); + + } else if (state->board_info[0] == 0xcc) { + if (state->type_flags & DST_TYPE_HAS_NEWTUNE) + state->type_flags &= ~DST_TYPE_HAS_NEWTUNE; + state->type_flags |= DST_TYPE_HAS_TS204; + dprintk(verbose, DST_INFO, 1, "DST type has TS=204 Daughterboard=[%d]", state->board_info[1]); + } + } + + return 0; +} + static int dst_get_device_id(struct dst_state *state) { u8 reply; @@ -855,15 +905,12 @@ static int dst_get_device_id(struct dst_state *state) state->dst_type = use_dst_type; dst_type_flags_print(state->type_flags); - if (state->type_flags & DST_TYPE_HAS_TS204) { - dst_packsize(state, 204); - } - return 0; } static int dst_probe(struct dst_state *state) { + sema_init(&state->dst_mutex, 1); if ((rdc_8820_reset(state)) < 0) { dprintk(verbose, DST_ERROR, 1, "RDC 8820 RESET Failed."); return -1; @@ -886,6 +933,13 @@ static int dst_probe(struct dst_state *state) dprintk(verbose, DST_INFO, 1, "MAC: Unsupported command"); return 0; } + if ((state->type_flags & DST_TYPE_HAS_MULTI_FE) || (state->type_flags & DST_TYPE_HAS_FW_BUILD)) { + if (dst_get_tuner_info(state) < 0) + dprintk(verbose, DST_INFO, 1, "Tuner: Unsupported command"); + } + if (state->type_flags & DST_TYPE_HAS_TS204) { + dst_packsize(state, 204); + } if (state->type_flags & DST_TYPE_HAS_FW_BUILD) { if (dst_fw_ver(state) < 0) { dprintk(verbose, DST_INFO, 1, "FW: Unsupported command"); @@ -907,21 +961,23 @@ static int dst_probe(struct dst_state *state) int dst_command(struct dst_state *state, u8 *data, u8 len) { u8 reply; + + down(&state->dst_mutex); if ((dst_comm_init(state)) < 0) { dprintk(verbose, DST_NOTICE, 1, "DST Communication Initialization Failed."); - return -1; + goto error; } if (write_dst(state, data, len)) { dprintk(verbose, DST_INFO, 1, "Tring to recover.. "); if ((dst_error_recovery(state)) < 0) { dprintk(verbose, DST_ERROR, 1, "Recovery Failed."); - return -1; + goto error; } - return -1; + goto error; } if ((dst_pio_disable(state)) < 0) { dprintk(verbose, DST_ERROR, 1, "PIO Disable Failed."); - return -1; + goto error; } if (state->type_flags & DST_TYPE_HAS_FW_1) udelay(3000); @@ -929,36 +985,41 @@ int dst_command(struct dst_state *state, u8 *data, u8 len) dprintk(verbose, DST_DEBUG, 1, "Trying to recover.. "); if ((dst_error_recovery(state)) < 0) { dprintk(verbose, DST_INFO, 1, "Recovery Failed."); - return -1; + goto error; } - return -1; + goto error; } if (reply != ACK) { dprintk(verbose, DST_INFO, 1, "write not acknowledged 0x%02x ", reply); - return -1; + goto error; } if (len >= 2 && data[0] == 0 && (data[1] == 1 || data[1] == 3)) - return 0; + goto error; if (state->type_flags & DST_TYPE_HAS_FW_1) udelay(3000); else udelay(2000); if (!dst_wait_dst_ready(state, NO_DELAY)) - return -1; + goto error; if (read_dst(state, state->rxbuffer, FIXED_COMM)) { dprintk(verbose, DST_DEBUG, 1, "Trying to recover.. "); if ((dst_error_recovery(state)) < 0) { dprintk(verbose, DST_INFO, 1, "Recovery failed."); - return -1; + goto error; } - return -1; + goto error; } if (state->rxbuffer[7] != dst_check_sum(state->rxbuffer, 7)) { dprintk(verbose, DST_INFO, 1, "checksum failure"); - return -1; + goto error; } - + up(&state->dst_mutex); return 0; + +error: + up(&state->dst_mutex); + return -EIO; + } EXPORT_SYMBOL(dst_command); @@ -1016,7 +1077,7 @@ static int dst_get_tuna(struct dst_state *state) return 0; state->diseq_flags &= ~(HAS_LOCK); if (!dst_wait_dst_ready(state, NO_DELAY)) - return 0; + return -EIO; if (state->type_flags & DST_TYPE_HAS_NEWTUNE) /* how to get variable length reply ???? */ retval = read_dst(state, state->rx_tuna, 10); @@ -1024,22 +1085,27 @@ static int dst_get_tuna(struct dst_state *state) retval = read_dst(state, &state->rx_tuna[2], FIXED_COMM); if (retval < 0) { dprintk(verbose, DST_DEBUG, 1, "read not successful"); - return 0; + return retval; } if (state->type_flags & DST_TYPE_HAS_NEWTUNE) { if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[0], 9)) { dprintk(verbose, DST_INFO, 1, "checksum failure ? "); - return 0; + return -EIO; } } else { if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[2], 7)) { dprintk(verbose, DST_INFO, 1, "checksum failure? "); - return 0; + return -EIO; } } if (state->rx_tuna[2] == 0 && state->rx_tuna[3] == 0) return 0; - state->decode_freq = ((state->rx_tuna[2] & 0x7f) << 8) + state->rx_tuna[3]; + if (state->dst_type == DST_TYPE_IS_SAT) { + state->decode_freq = ((state->rx_tuna[2] & 0x7f) << 8) + state->rx_tuna[3]; + } else { + state->decode_freq = ((state->rx_tuna[2] & 0x7f) << 16) + (state->rx_tuna[3] << 8) + state->rx_tuna[4]; + } + state->decode_freq = state->decode_freq * 1000; state->decode_lock = 1; state->diseq_flags |= HAS_LOCK; @@ -1062,10 +1128,10 @@ static int dst_write_tuna(struct dvb_frontend *fe) dst_set_voltage(fe, SEC_VOLTAGE_13); } state->diseq_flags &= ~(HAS_LOCK | ATTEMPT_TUNE); - + down(&state->dst_mutex); if ((dst_comm_init(state)) < 0) { dprintk(verbose, DST_DEBUG, 1, "DST Communication initialization failed."); - return -1; + goto error; } if (state->type_flags & DST_TYPE_HAS_NEWTUNE) { state->tx_tuna[9] = dst_check_sum(&state->tx_tuna[0], 9); @@ -1077,23 +1143,29 @@ static int dst_write_tuna(struct dvb_frontend *fe) if (retval < 0) { dst_pio_disable(state); dprintk(verbose, DST_DEBUG, 1, "write not successful"); - return retval; + goto werr; } if ((dst_pio_disable(state)) < 0) { dprintk(verbose, DST_DEBUG, 1, "DST PIO disable failed !"); - return -1; + goto error; } if ((read_dst(state, &reply, GET_ACK) < 0)) { dprintk(verbose, DST_DEBUG, 1, "read verify not successful."); - return -1; + goto error; } if (reply != ACK) { dprintk(verbose, DST_DEBUG, 1, "write not acknowledged 0x%02x ", reply); - return 0; + goto error; } state->diseq_flags |= ATTEMPT_TUNE; - - return dst_get_tuna(state); + retval = dst_get_tuna(state); +werr: + up(&state->dst_mutex); + return retval; + +error: + up(&state->dst_mutex); + return -EIO; } /* @@ -1331,9 +1403,7 @@ struct dst_state *dst_attach(struct dst_state *state, struct dvb_adapter *dvb_ad { /* check if the ASIC is there */ if (dst_probe(state) < 0) { - if (state) - kfree(state); - + kfree(state); return NULL; } /* determine settings based on type */ @@ -1349,9 +1419,7 @@ struct dst_state *dst_attach(struct dst_state *state, struct dvb_adapter *dvb_ad break; default: dprintk(verbose, DST_ERROR, 1, "unknown DST type. please report to the LinuxTV.org DVB mailinglist."); - if (state) - kfree(state); - + kfree(state); return NULL; } diff --git a/drivers/media/dvb/bt8xx/dst_ca.c b/drivers/media/dvb/bt8xx/dst_ca.c index 6776a592045f..e6541aff3996 100644 --- a/drivers/media/dvb/bt8xx/dst_ca.c +++ b/drivers/media/dvb/bt8xx/dst_ca.c @@ -69,62 +69,53 @@ static int ca_set_pid(void) } -static int put_checksum(u8 *check_string, int length) +static void put_checksum(u8 *check_string, int length) { - u8 i = 0, checksum = 0; - - dprintk(verbose, DST_CA_DEBUG, 1, " ========================= Checksum calculation ==========================="); - dprintk(verbose, DST_CA_DEBUG, 1, " String Length=[0x%02x]", length); - dprintk(verbose, DST_CA_DEBUG, 1, " String=["); - - while (i < length) { - dprintk(verbose, DST_CA_DEBUG, 0, " %02x", check_string[i]); - checksum += check_string[i]; - i++; - } - dprintk(verbose, DST_CA_DEBUG, 0, " ]\n"); - dprintk(verbose, DST_CA_DEBUG, 1, "Sum=[%02x]\n", checksum); - check_string[length] = ~checksum + 1; - dprintk(verbose, DST_CA_DEBUG, 1, " Checksum=[%02x]", check_string[length]); - dprintk(verbose, DST_CA_DEBUG, 1, " =========================================================================="); - - return 0; + dprintk(verbose, DST_CA_DEBUG, 1, " Computing string checksum."); + dprintk(verbose, DST_CA_DEBUG, 1, " -> string length : 0x%02x", length); + check_string[length] = dst_check_sum (check_string, length); + dprintk(verbose, DST_CA_DEBUG, 1, " -> checksum : 0x%02x", check_string[length]); } static int dst_ci_command(struct dst_state* state, u8 * data, u8 *ca_string, u8 len, int read) { u8 reply; + down(&state->dst_mutex); dst_comm_init(state); msleep(65); if (write_dst(state, data, len)) { dprintk(verbose, DST_CA_INFO, 1, " Write not successful, trying to recover"); dst_error_recovery(state); - return -1; + goto error; } if ((dst_pio_disable(state)) < 0) { dprintk(verbose, DST_CA_ERROR, 1, " DST PIO disable failed."); - return -1; + goto error; } if (read_dst(state, &reply, GET_ACK) < 0) { dprintk(verbose, DST_CA_INFO, 1, " Read not successful, trying to recover"); dst_error_recovery(state); - return -1; + goto error; } if (read) { if (! dst_wait_dst_ready(state, LONG_DELAY)) { dprintk(verbose, DST_CA_NOTICE, 1, " 8820 not ready"); - return -1; + goto error; } if (read_dst(state, ca_string, 128) < 0) { /* Try to make this dynamic */ dprintk(verbose, DST_CA_INFO, 1, " Read not successful, trying to recover"); dst_error_recovery(state); - return -1; + goto error; } } - + up(&state->dst_mutex); return 0; + +error: + up(&state->dst_mutex); + return -EIO; } @@ -166,7 +157,7 @@ static int ca_get_app_info(struct dst_state *state) return 0; } -static int ca_get_slot_caps(struct dst_state *state, struct ca_caps *p_ca_caps, void *arg) +static int ca_get_slot_caps(struct dst_state *state, struct ca_caps *p_ca_caps, void __user *arg) { int i; u8 slot_cap[256]; @@ -192,25 +183,25 @@ static int ca_get_slot_caps(struct dst_state *state, struct ca_caps *p_ca_caps, p_ca_caps->descr_num = slot_cap[7]; p_ca_caps->descr_type = 1; - if (copy_to_user((struct ca_caps *)arg, p_ca_caps, sizeof (struct ca_caps))) + if (copy_to_user(arg, p_ca_caps, sizeof (struct ca_caps))) return -EFAULT; return 0; } /* Need some more work */ -static int ca_get_slot_descr(struct dst_state *state, struct ca_msg *p_ca_message, void *arg) +static int ca_get_slot_descr(struct dst_state *state, struct ca_msg *p_ca_message, void __user *arg) { return -EOPNOTSUPP; } -static int ca_get_slot_info(struct dst_state *state, struct ca_slot_info *p_ca_slot_info, void *arg) +static int ca_get_slot_info(struct dst_state *state, struct ca_slot_info *p_ca_slot_info, void __user *arg) { int i; static u8 slot_command[8] = {0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff}; - u8 *slot_info = state->rxbuffer; + u8 *slot_info = state->messages; put_checksum(&slot_command[0], 7); if ((dst_put_ci(state, slot_command, sizeof (slot_command), slot_info, GET_REPLY)) < 0) { @@ -238,19 +229,19 @@ static int ca_get_slot_info(struct dst_state *state, struct ca_slot_info *p_ca_s } else p_ca_slot_info->flags = 0; - if (copy_to_user((struct ca_slot_info *)arg, p_ca_slot_info, sizeof (struct ca_slot_info))) + if (copy_to_user(arg, p_ca_slot_info, sizeof (struct ca_slot_info))) return -EFAULT; return 0; } -static int ca_get_message(struct dst_state *state, struct ca_msg *p_ca_message, void *arg) +static int ca_get_message(struct dst_state *state, struct ca_msg *p_ca_message, void __user *arg) { u8 i = 0; u32 command = 0; - if (copy_from_user(p_ca_message, (void *)arg, sizeof (struct ca_msg))) + if (copy_from_user(p_ca_message, arg, sizeof (struct ca_msg))) return -EFAULT; if (p_ca_message->msg) { @@ -266,7 +257,7 @@ static int ca_get_message(struct dst_state *state, struct ca_msg *p_ca_message, switch (command) { case CA_APP_INFO: memcpy(p_ca_message->msg, state->messages, 128); - if (copy_to_user((void *)arg, p_ca_message, sizeof (struct ca_msg)) ) + if (copy_to_user(arg, p_ca_message, sizeof (struct ca_msg)) ) return -EFAULT; break; } @@ -315,7 +306,7 @@ static int write_to_8820(struct dst_state *state, struct ca_msg *hw_buffer, u8 l return 0; } -u32 asn_1_decode(u8 *asn_1_array) +static u32 asn_1_decode(u8 *asn_1_array) { u8 length_field = 0, word_count = 0, count = 0; u32 length = 0; @@ -328,7 +319,8 @@ u32 asn_1_decode(u8 *asn_1_array) } else { word_count = length_field & 0x7f; for (count = 0; count < word_count; count++) { - length = (length | asn_1_array[count + 1]) << 8; + length = length << 8; + length += asn_1_array[count + 1]; dprintk(verbose, DST_CA_DEBUG, 1, " Length=[%04x]", length); } } @@ -399,13 +391,14 @@ static int dst_check_ca_pmt(struct dst_state *state, struct ca_msg *p_ca_message return 0; } -static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message, void *arg) +static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message, void __user *arg) { int i = 0; unsigned int ca_message_header_len; u32 command = 0; struct ca_msg *hw_buffer; + int result = 0; if ((hw_buffer = (struct ca_msg *) kmalloc(sizeof (struct ca_msg), GFP_KERNEL)) == NULL) { dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure"); @@ -413,8 +406,11 @@ static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message, } dprintk(verbose, DST_CA_DEBUG, 1, " "); - if (copy_from_user(p_ca_message, (void *)arg, sizeof (struct ca_msg))) - return -EFAULT; + if (copy_from_user(p_ca_message, (void *)arg, sizeof (struct ca_msg))) { + result = -EFAULT; + goto free_mem_and_exit; + } + if (p_ca_message->msg) { ca_message_header_len = p_ca_message->length; /* Restore it back when you are done */ @@ -433,7 +429,8 @@ static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message, dprintk(verbose, DST_CA_DEBUG, 1, "Command = SEND_CA_PMT"); if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, 0)) < 0) { // code simplification started dprintk(verbose, DST_CA_ERROR, 1, " -->CA_PMT Failed !"); - return -1; + result = -1; + goto free_mem_and_exit; } dprintk(verbose, DST_CA_INFO, 1, " -->CA_PMT Success !"); break; @@ -442,7 +439,8 @@ static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message, /* Have to handle the 2 basic types of cards here */ if ((dst_check_ca_pmt(state, p_ca_message, hw_buffer)) < 0) { dprintk(verbose, DST_CA_ERROR, 1, " -->CA_PMT_REPLY Failed !"); - return -1; + result = -1; + goto free_mem_and_exit; } dprintk(verbose, DST_CA_INFO, 1, " -->CA_PMT_REPLY Success !"); break; @@ -451,22 +449,28 @@ static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message, if ((ca_get_app_info(state)) < 0) { dprintk(verbose, DST_CA_ERROR, 1, " -->CA_APP_INFO_ENQUIRY Failed !"); - return -1; + result = -1; + goto free_mem_and_exit; } dprintk(verbose, DST_CA_INFO, 1, " -->CA_APP_INFO_ENQUIRY Success !"); break; } } - return 0; +free_mem_and_exit: + kfree (hw_buffer); + + return result; } -static int dst_ca_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *arg) +static int dst_ca_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long ioctl_arg) { struct dvb_device* dvbdev = (struct dvb_device*) file->private_data; struct dst_state* state = (struct dst_state*) dvbdev->priv; struct ca_slot_info *p_ca_slot_info; struct ca_caps *p_ca_caps; struct ca_msg *p_ca_message; + void __user *arg = (void __user *)ioctl_arg; + int result = 0; if ((p_ca_message = (struct ca_msg *) kmalloc(sizeof (struct ca_msg), GFP_KERNEL)) == NULL) { dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure"); @@ -486,14 +490,16 @@ static int dst_ca_ioctl(struct inode *inode, struct file *file, unsigned int cmd dprintk(verbose, DST_CA_INFO, 1, " Sending message"); if ((ca_send_message(state, p_ca_message, arg)) < 0) { dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SEND_MSG Failed !"); - return -1; + result = -1; + goto free_mem_and_exit; } break; case CA_GET_MSG: dprintk(verbose, DST_CA_INFO, 1, " Getting message"); if ((ca_get_message(state, p_ca_message, arg)) < 0) { dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_MSG Failed !"); - return -1; + result = -1; + goto free_mem_and_exit; } dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_MSG Success !"); break; @@ -506,7 +512,8 @@ static int dst_ca_ioctl(struct inode *inode, struct file *file, unsigned int cmd dprintk(verbose, DST_CA_INFO, 1, " Getting Slot info"); if ((ca_get_slot_info(state, p_ca_slot_info, arg)) < 0) { dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_SLOT_INFO Failed !"); - return -1; + result = -1; + goto free_mem_and_exit; } dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_SLOT_INFO Success !"); break; @@ -514,7 +521,8 @@ static int dst_ca_ioctl(struct inode *inode, struct file *file, unsigned int cmd dprintk(verbose, DST_CA_INFO, 1, " Getting Slot capabilities"); if ((ca_get_slot_caps(state, p_ca_caps, arg)) < 0) { dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_CAP Failed !"); - return -1; + result = -1; + goto free_mem_and_exit; } dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_CAP Success !"); break; @@ -522,7 +530,8 @@ static int dst_ca_ioctl(struct inode *inode, struct file *file, unsigned int cmd dprintk(verbose, DST_CA_INFO, 1, " Getting descrambler description"); if ((ca_get_slot_descr(state, p_ca_message, arg)) < 0) { dprintk(verbose, DST_CA_ERROR, 1, " -->CA_GET_DESCR_INFO Failed !"); - return -1; + result = -1; + goto free_mem_and_exit; } dprintk(verbose, DST_CA_INFO, 1, " -->CA_GET_DESCR_INFO Success !"); break; @@ -530,7 +539,8 @@ static int dst_ca_ioctl(struct inode *inode, struct file *file, unsigned int cmd dprintk(verbose, DST_CA_INFO, 1, " Setting descrambler"); if ((ca_set_slot_descr()) < 0) { dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SET_DESCR Failed !"); - return -1; + result = -1; + goto free_mem_and_exit; } dprintk(verbose, DST_CA_INFO, 1, " -->CA_SET_DESCR Success !"); break; @@ -538,14 +548,19 @@ static int dst_ca_ioctl(struct inode *inode, struct file *file, unsigned int cmd dprintk(verbose, DST_CA_INFO, 1, " Setting PID"); if ((ca_set_pid()) < 0) { dprintk(verbose, DST_CA_ERROR, 1, " -->CA_SET_PID Failed !"); - return -1; + result = -1; + goto free_mem_and_exit; } dprintk(verbose, DST_CA_INFO, 1, " -->CA_SET_PID Success !"); default: - return -EOPNOTSUPP; + result = -EOPNOTSUPP; }; + free_mem_and_exit: + kfree (p_ca_message); + kfree (p_ca_slot_info); + kfree (p_ca_caps); - return 0; + return result; } static int dst_ca_open(struct inode *inode, struct file *file) @@ -582,7 +597,7 @@ static int dst_ca_write(struct file *file, const char __user *buffer, size_t len static struct file_operations dst_ca_fops = { .owner = THIS_MODULE, - .ioctl = (void *)dst_ca_ioctl, + .ioctl = dst_ca_ioctl, .open = dst_ca_open, .release = dst_ca_release, .read = dst_ca_read, diff --git a/drivers/media/dvb/bt8xx/dst_common.h b/drivers/media/dvb/bt8xx/dst_common.h index 3281a6ca3685..81557f38fe38 100644 --- a/drivers/media/dvb/bt8xx/dst_common.h +++ b/drivers/media/dvb/bt8xx/dst_common.h @@ -22,6 +22,7 @@ #ifndef DST_COMMON_H #define DST_COMMON_H +#include <linux/smp_lock.h> #include <linux/dvb/frontend.h> #include <linux/device.h> #include "bt878.h" @@ -49,6 +50,7 @@ #define DST_TYPE_HAS_FW_BUILD 64 #define DST_TYPE_HAS_OBS_REGS 128 #define DST_TYPE_HAS_INC_COUNT 256 +#define DST_TYPE_HAS_MULTI_FE 512 /* Card capability list */ @@ -117,6 +119,9 @@ struct dst_state { u8 fw_version[8]; u8 card_info[8]; u8 vendor[8]; + u8 board_info[8]; + + struct semaphore dst_mutex; }; struct dst_types { diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c index c5c7672cd538..2e398090cf63 100644 --- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c +++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c @@ -34,6 +34,7 @@ #include "dvb_frontend.h" #include "dvb-bt8xx.h" #include "bt878.h" +#include "dvb-pll.h" static int debug; @@ -279,7 +280,7 @@ static int microtune_mt7202dtf_pll_set(struct dvb_frontend* fe, struct dvb_front data[0] = (div >> 8) & 0x7f; data[1] = div & 0xff; data[2] = ((div >> 10) & 0x60) | cfg; - data[3] = cpump | band_select; + data[3] = (cpump << 6) | band_select; i2c_transfer(card->i2c_adapter, &msg, 1); return (div * 166666 - 36000000); @@ -522,9 +523,7 @@ static void digitv_alps_tded4_reset(struct dvb_bt8xx_card *bt) /* * Reset the frontend, must be called before trying * to initialise the MT352 or mt352_attach - * will fail. - * - * Presumably not required for the NXT6000 frontend. + * will fail. Same goes for the nxt6000 frontend. * */ @@ -546,14 +545,63 @@ static struct mt352_config digitv_alps_tded4_config = { .pll_set = digitv_alps_tded4_pll_set, }; +static int tdvs_tua6034_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +{ + struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv; + u8 buf[4]; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; + int err; + + dvb_pll_configure(&dvb_pll_tdvs_tua6034, buf, params->frequency, 0); + dprintk("%s: tuner at 0x%02x bytes: 0x%02x 0x%02x 0x%02x 0x%02x\n", + __FUNCTION__, msg.addr, buf[0],buf[1],buf[2],buf[3]); + if ((err = i2c_transfer(card->i2c_adapter, &msg, 1)) != 1) { + printk(KERN_WARNING "dvb-bt8xx: %s error " + "(addr %02x <- %02x, err = %i)\n", + __FUNCTION__, buf[0], buf[1], err); + if (err < 0) + return err; + else + return -EREMOTEIO; + } + + /* Set the Auxiliary Byte. */ + buf[2] &= ~0x20; + buf[2] |= 0x18; + buf[3] = 0x50; + i2c_transfer(card->i2c_adapter, &msg, 1); + + return 0; +} + +static struct lgdt330x_config tdvs_tua6034_config = { + .demod_address = 0x0e, + .demod_chip = LGDT3303, + .serial_mpeg = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */ + .pll_set = tdvs_tua6034_pll_set, +}; + +static void lgdt330x_reset(struct dvb_bt8xx_card *bt) +{ + /* Set pin 27 of the lgdt3303 chip high to reset the frontend */ + + /* Pulse the reset line */ + bttv_write_gpio(bt->bttv_nr, 0x00e00007, 0x00000001); /* High */ + bttv_write_gpio(bt->bttv_nr, 0x00e00007, 0x00000000); /* Low */ + msleep(100); + + bttv_write_gpio(bt->bttv_nr, 0x00e00007, 0x00000001); /* High */ + msleep(100); +} + static void frontend_init(struct dvb_bt8xx_card *card, u32 type) { int ret; struct dst_state* state = NULL; switch(type) { -#ifdef BTTV_DVICO_DVBT_LITE - case BTTV_DVICO_DVBT_LITE: +#ifdef BTTV_BOARD_DVICO_DVBT_LITE + case BTTV_BOARD_DVICO_DVBT_LITE: card->fe = mt352_attach(&thomson_dtt7579_config, card->i2c_adapter); if (card->fe != NULL) { card->fe->ops->info.frequency_min = 174000000; @@ -562,10 +610,19 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type) break; #endif -#ifdef BTTV_TWINHAN_VP3021 - case BTTV_TWINHAN_VP3021: +#ifdef BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE + case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE: + lgdt330x_reset(card); + card->fe = lgdt330x_attach(&tdvs_tua6034_config, card->i2c_adapter); + if (card->fe != NULL) + dprintk ("dvb_bt8xx: lgdt330x detected\n"); + break; +#endif + +#ifdef BTTV_BOARD_TWINHAN_VP3021 + case BTTV_BOARD_TWINHAN_VP3021: #else - case BTTV_NEBULA_DIGITV: + case BTTV_BOARD_NEBULA_DIGITV: #endif /* * It is possible to determine the correct frontend using the I2C bus (see the Nebula SDK); @@ -573,6 +630,7 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type) */ /* Old Nebula (marked (c)2003 on high profile pci card) has nxt6000 demod */ + digitv_alps_tded4_reset(card); card->fe = nxt6000_attach(&vp3021_alps_tded4_config, card->i2c_adapter); if (card->fe != NULL) { dprintk ("dvb_bt8xx: an nxt6000 was detected on your digitv card\n"); @@ -587,11 +645,11 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type) dprintk ("dvb_bt8xx: an mt352 was detected on your digitv card\n"); break; - case BTTV_AVDVBT_761: + case BTTV_BOARD_AVDVBT_761: card->fe = sp887x_attach(µtune_mt7202dtf_config, card->i2c_adapter); break; - case BTTV_AVDVBT_771: + case BTTV_BOARD_AVDVBT_771: card->fe = mt352_attach(&advbt771_samsung_tdtc9251dh0_config, card->i2c_adapter); if (card->fe != NULL) { card->fe->ops->info.frequency_min = 174000000; @@ -599,7 +657,7 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type) } break; - case BTTV_TWINHAN_DST: + case BTTV_BOARD_TWINHAN_DST: /* DST is not a frontend driver !!! */ state = (struct dst_state *) kmalloc(sizeof (struct dst_state), GFP_KERNEL); /* Setup the Card */ @@ -620,11 +678,11 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type) ret = dst_ca_attach(state, &card->dvb_adapter); break; - case BTTV_PINNACLESAT: + case BTTV_BOARD_PINNACLESAT: card->fe = cx24110_attach(&pctvsat_config, card->i2c_adapter); break; - case BTTV_PC_HDTV: + case BTTV_BOARD_PC_HDTV: card->fe = or51211_attach(&or51211_config, card->i2c_adapter); break; } @@ -746,7 +804,7 @@ static int dvb_bt8xx_probe(struct device *dev) card->i2c_adapter = &sub->core->i2c_adap; switch(sub->core->type) { - case BTTV_PINNACLESAT: + case BTTV_BOARD_PINNACLESAT: card->gpio_mode = 0x0400c060; /* should be: BT878_A_GAIN=0,BT878_A_PWRDN,BT878_DA_DPM,BT878_DA_SBR, BT878_DA_IOM=1,BT878_DA_APP to enable serial highspeed mode. */ @@ -754,8 +812,8 @@ static int dvb_bt8xx_probe(struct device *dev) card->irq_err_ignore = 0; break; -#ifdef BTTV_DVICO_DVBT_LITE - case BTTV_DVICO_DVBT_LITE: +#ifdef BTTV_BOARD_DVICO_DVBT_LITE + case BTTV_BOARD_DVICO_DVBT_LITE: #endif card->gpio_mode = 0x0400C060; card->op_sync_orin = 0; @@ -765,26 +823,34 @@ static int dvb_bt8xx_probe(struct device *dev) * DA_APP(parallel) */ break; -#ifdef BTTV_TWINHAN_VP3021 - case BTTV_TWINHAN_VP3021: +#ifdef BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE + case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE: +#endif + card->gpio_mode = 0x0400c060; + card->op_sync_orin = BT878_RISC_SYNC_MASK; + card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR; + break; + +#ifdef BTTV_BOARD_TWINHAN_VP3021 + case BTTV_BOARD_TWINHAN_VP3021: #else - case BTTV_NEBULA_DIGITV: + case BTTV_BOARD_NEBULA_DIGITV: #endif - case BTTV_AVDVBT_761: + case BTTV_BOARD_AVDVBT_761: card->gpio_mode = (1 << 26) | (1 << 14) | (1 << 5); card->op_sync_orin = 0; card->irq_err_ignore = 0; /* A_PWRDN DA_SBR DA_APP (high speed serial) */ break; - case BTTV_AVDVBT_771: //case 0x07711461: + case BTTV_BOARD_AVDVBT_771: //case 0x07711461: card->gpio_mode = 0x0400402B; card->op_sync_orin = BT878_RISC_SYNC_MASK; card->irq_err_ignore = 0; /* A_PWRDN DA_SBR DA_APP[0] PKTP=10 RISC_ENABLE FIFO_ENABLE*/ break; - case BTTV_TWINHAN_DST: + case BTTV_BOARD_TWINHAN_DST: card->gpio_mode = 0x2204f2c; card->op_sync_orin = BT878_RISC_SYNC_MASK; card->irq_err_ignore = BT878_APABORT | BT878_ARIPERR | @@ -802,7 +868,7 @@ static int dvb_bt8xx_probe(struct device *dev) * RISC+FIFO ENABLE */ break; - case BTTV_PC_HDTV: + case BTTV_BOARD_PC_HDTV: card->gpio_mode = 0x0100EC7B; card->op_sync_orin = 0; card->irq_err_ignore = 0; diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.h b/drivers/media/dvb/bt8xx/dvb-bt8xx.h index 9ec8e5bd6c1f..cf035a80361c 100644 --- a/drivers/media/dvb/bt8xx/dvb-bt8xx.h +++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.h @@ -35,6 +35,7 @@ #include "nxt6000.h" #include "cx24110.h" #include "or51211.h" +#include "lgdt330x.h" struct dvb_bt8xx_card { struct semaphore lock; diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c index 6db0929ef53d..336fc284fa52 100644 --- a/drivers/media/dvb/cinergyT2/cinergyT2.c +++ b/drivers/media/dvb/cinergyT2/cinergyT2.c @@ -137,7 +137,8 @@ struct cinergyt2 { struct urb *stream_urb [STREAM_URB_COUNT]; #ifdef ENABLE_RC - struct input_dev rc_input_dev; + struct input_dev *rc_input_dev; + char phys[64]; struct work_struct rc_query_work; int rc_input_event; u32 rc_last_code; @@ -275,7 +276,7 @@ static void cinergyt2_free_stream_urbs (struct cinergyt2 *cinergyt2) if (cinergyt2->stream_urb[i]) usb_free_urb(cinergyt2->stream_urb[i]); - pci_free_consistent(NULL, STREAM_URB_COUNT*STREAM_BUF_SIZE, + usb_buffer_free(cinergyt2->udev, STREAM_URB_COUNT*STREAM_BUF_SIZE, cinergyt2->streambuf, cinergyt2->streambuf_dmahandle); } @@ -283,9 +284,8 @@ static int cinergyt2_alloc_stream_urbs (struct cinergyt2 *cinergyt2) { int i; - cinergyt2->streambuf = pci_alloc_consistent(NULL, - STREAM_URB_COUNT*STREAM_BUF_SIZE, - &cinergyt2->streambuf_dmahandle); + cinergyt2->streambuf = usb_buffer_alloc(cinergyt2->udev, STREAM_URB_COUNT*STREAM_BUF_SIZE, + SLAB_KERNEL, &cinergyt2->streambuf_dmahandle); if (!cinergyt2->streambuf) { dprintk(1, "failed to alloc consistent stream memory area, bailing out!\n"); return -ENOMEM; @@ -683,6 +683,7 @@ static struct dvb_device cinergyt2_fe_template = { }; #ifdef ENABLE_RC + static void cinergyt2_query_rc (void *data) { struct cinergyt2 *cinergyt2 = data; @@ -703,7 +704,7 @@ static void cinergyt2_query_rc (void *data) /* stop key repeat */ if (cinergyt2->rc_input_event != KEY_MAX) { dprintk(1, "rc_input_event=%d Up\n", cinergyt2->rc_input_event); - input_report_key(&cinergyt2->rc_input_dev, + input_report_key(cinergyt2->rc_input_dev, cinergyt2->rc_input_event, 0); cinergyt2->rc_input_event = KEY_MAX; } @@ -722,7 +723,7 @@ static void cinergyt2_query_rc (void *data) /* keyrepeat bit -> just repeat last rc_input_event */ } else { cinergyt2->rc_input_event = KEY_MAX; - for (i = 0; i < sizeof(rc_keys) / sizeof(rc_keys[0]); i += 3) { + for (i = 0; i < ARRAY_SIZE(rc_keys); i += 3) { if (rc_keys[i + 0] == rc_events[n].type && rc_keys[i + 1] == le32_to_cpu(rc_events[n].value)) { cinergyt2->rc_input_event = rc_keys[i + 2]; @@ -736,11 +737,11 @@ static void cinergyt2_query_rc (void *data) cinergyt2->rc_last_code != ~0) { /* emit a key-up so the double event is recognized */ dprintk(1, "rc_input_event=%d UP\n", cinergyt2->rc_input_event); - input_report_key(&cinergyt2->rc_input_dev, + input_report_key(cinergyt2->rc_input_dev, cinergyt2->rc_input_event, 0); } dprintk(1, "rc_input_event=%d\n", cinergyt2->rc_input_event); - input_report_key(&cinergyt2->rc_input_dev, + input_report_key(cinergyt2->rc_input_dev, cinergyt2->rc_input_event, 1); cinergyt2->rc_last_code = rc_events[n].value; } @@ -752,7 +753,61 @@ out: up(&cinergyt2->sem); } -#endif + +static int cinergyt2_register_rc(struct cinergyt2 *cinergyt2) +{ + struct input_dev *input_dev; + int i; + + cinergyt2->rc_input_dev = input_dev = input_allocate_device(); + if (!input_dev) + return -ENOMEM; + + usb_make_path(cinergyt2->udev, cinergyt2->phys, sizeof(cinergyt2->phys)); + strlcat(cinergyt2->phys, "/input0", sizeof(cinergyt2->phys)); + cinergyt2->rc_input_event = KEY_MAX; + cinergyt2->rc_last_code = ~0; + INIT_WORK(&cinergyt2->rc_query_work, cinergyt2_query_rc, cinergyt2); + + input_dev->name = DRIVER_NAME " remote control"; + input_dev->phys = cinergyt2->phys; + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + for (i = 0; i < ARRAY_SIZE(rc_keys); i += 3) + set_bit(rc_keys[i + 2], input_dev->keybit); + input_dev->keycodesize = 0; + input_dev->keycodemax = 0; + + input_register_device(cinergyt2->rc_input_dev); + schedule_delayed_work(&cinergyt2->rc_query_work, HZ/2); + + return 0; +} + +static void cinergyt2_unregister_rc(struct cinergyt2 *cinergyt2) +{ + cancel_delayed_work(&cinergyt2->rc_query_work); + flush_scheduled_work(); + input_unregister_device(cinergyt2->rc_input_dev); +} + +static inline void cinergyt2_suspend_rc(struct cinergyt2 *cinergyt2) +{ + cancel_delayed_work(&cinergyt2->rc_query_work); +} + +static inline void cinergyt2_resume_rc(struct cinergyt2 *cinergyt2) +{ + schedule_delayed_work(&cinergyt2->rc_query_work, HZ/2); +} + +#else + +static inline int cinergyt2_register_rc(struct cinergyt2 *cinergyt2) { return 0; } +static inline void cinergyt2_unregister_rc(struct cinergyt2 *cinergyt2) { } +static inline void cinergyt2_suspend_rc(struct cinergyt2 *cinergyt2) { } +static inline void cinergyt2_resume_rc(struct cinergyt2 *cinergyt2) { } + +#endif /* ENABLE_RC */ static void cinergyt2_query (void *data) { @@ -789,9 +844,6 @@ static int cinergyt2_probe (struct usb_interface *intf, { struct cinergyt2 *cinergyt2; int err; -#ifdef ENABLE_RC - int i; -#endif if (!(cinergyt2 = kmalloc (sizeof(struct cinergyt2), GFP_KERNEL))) { dprintk(1, "out of memory?!?\n"); @@ -846,30 +898,17 @@ static int cinergyt2_probe (struct usb_interface *intf, &cinergyt2_fe_template, cinergyt2, DVB_DEVICE_FRONTEND); -#ifdef ENABLE_RC - cinergyt2->rc_input_dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); - cinergyt2->rc_input_dev.keycodesize = 0; - cinergyt2->rc_input_dev.keycodemax = 0; - cinergyt2->rc_input_dev.name = DRIVER_NAME " remote control"; - - for (i = 0; i < sizeof(rc_keys) / sizeof(rc_keys[0]); i += 3) - set_bit(rc_keys[i + 2], cinergyt2->rc_input_dev.keybit); - - input_register_device(&cinergyt2->rc_input_dev); - - cinergyt2->rc_input_event = KEY_MAX; - cinergyt2->rc_last_code = ~0; + err = cinergyt2_register_rc(cinergyt2); + if (err) + goto bailout; - INIT_WORK(&cinergyt2->rc_query_work, cinergyt2_query_rc, cinergyt2); - schedule_delayed_work(&cinergyt2->rc_query_work, HZ/2); -#endif return 0; bailout: dvb_dmxdev_release(&cinergyt2->dmxdev); dvb_dmx_release(&cinergyt2->demux); - dvb_unregister_adapter (&cinergyt2->adapter); - cinergyt2_free_stream_urbs (cinergyt2); + dvb_unregister_adapter(&cinergyt2->adapter); + cinergyt2_free_stream_urbs(cinergyt2); kfree(cinergyt2); return -ENOMEM; } @@ -881,11 +920,7 @@ static void cinergyt2_disconnect (struct usb_interface *intf) if (down_interruptible(&cinergyt2->sem)) return; -#ifdef ENABLE_RC - cancel_delayed_work(&cinergyt2->rc_query_work); - flush_scheduled_work(); - input_unregister_device(&cinergyt2->rc_input_dev); -#endif + cinergyt2_unregister_rc(cinergyt2); cinergyt2->demux.dmx.close(&cinergyt2->demux.dmx); dvb_net_release(&cinergyt2->dvbnet); @@ -908,9 +943,8 @@ static int cinergyt2_suspend (struct usb_interface *intf, pm_message_t state) if (state.event > PM_EVENT_ON) { struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf); -#ifdef ENABLE_RC - cancel_delayed_work(&cinergyt2->rc_query_work); -#endif + + cinergyt2_suspend_rc(cinergyt2); cancel_delayed_work(&cinergyt2->query_work); if (cinergyt2->streaming) cinergyt2_stop_stream_xfer(cinergyt2); @@ -938,9 +972,8 @@ static int cinergyt2_resume (struct usb_interface *intf) schedule_delayed_work(&cinergyt2->query_work, HZ/2); } -#ifdef ENABLE_RC - schedule_delayed_work(&cinergyt2->rc_query_work, HZ/2); -#endif + cinergyt2_resume_rc(cinergyt2); + up(&cinergyt2->sem); return 0; } diff --git a/drivers/media/dvb/dvb-core/demux.h b/drivers/media/dvb/dvb-core/demux.h index 9719a3b30f78..7d7b0067f228 100644 --- a/drivers/media/dvb/dvb-core/demux.h +++ b/drivers/media/dvb/dvb-core/demux.h @@ -48,8 +48,11 @@ * DMX_MAX_SECFEED_SIZE: Maximum length (in bytes) of a private section feed filter. */ +#ifndef DMX_MAX_SECTION_SIZE +#define DMX_MAX_SECTION_SIZE 4096 +#endif #ifndef DMX_MAX_SECFEED_SIZE -#define DMX_MAX_SECFEED_SIZE 4096 +#define DMX_MAX_SECFEED_SIZE (DMX_MAX_SECTION_SIZE + 188) #endif diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c index 88757e2634e5..cb2e7d6ba283 100644 --- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c +++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c @@ -35,7 +35,8 @@ #include <linux/moduleparam.h> #include <linux/vmalloc.h> #include <linux/delay.h> -#include <linux/rwsem.h> +#include <linux/spinlock.h> +#include <linux/sched.h> #include "dvb_ca_en50221.h" #include "dvb_ringbuffer.h" @@ -110,9 +111,6 @@ struct dvb_ca_slot { /* size of the buffer to use when talking to the CAM */ int link_buf_size; - /* semaphore for syncing access to slot structure */ - struct rw_semaphore sem; - /* buffer for incoming packets */ struct dvb_ringbuffer rx_buffer; @@ -601,14 +599,11 @@ static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot, u8 * eb if (ebuf == NULL) { int buf_free; - down_read(&ca->slot_info[slot].sem); if (ca->slot_info[slot].rx_buffer.data == NULL) { - up_read(&ca->slot_info[slot].sem); status = -EIO; goto exit; } buf_free = dvb_ringbuffer_free(&ca->slot_info[slot].rx_buffer); - up_read(&ca->slot_info[slot].sem); if (buf_free < (ca->slot_info[slot].link_buf_size + DVB_RINGBUFFER_PKTHDRSIZE)) { status = -EAGAIN; @@ -679,14 +674,11 @@ static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot, u8 * eb /* OK, add it to the receive buffer, or copy into external buffer if supplied */ if (ebuf == NULL) { - down_read(&ca->slot_info[slot].sem); if (ca->slot_info[slot].rx_buffer.data == NULL) { - up_read(&ca->slot_info[slot].sem); status = -EIO; goto exit; } dvb_ringbuffer_pkt_write(&ca->slot_info[slot].rx_buffer, buf, bytes_read); - up_read(&ca->slot_info[slot].sem); } else { memcpy(ebuf, buf, bytes_read); } @@ -801,12 +793,8 @@ static int dvb_ca_en50221_slot_shutdown(struct dvb_ca_private *ca, int slot) { dprintk("%s\n", __FUNCTION__); - down_write(&ca->slot_info[slot].sem); ca->pub->slot_shutdown(ca->pub, slot); ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE; - vfree(ca->slot_info[slot].rx_buffer.data); - ca->slot_info[slot].rx_buffer.data = NULL; - up_write(&ca->slot_info[slot].sem); /* need to wake up all processes to check if they're now trying to write to a defunct CAM */ @@ -892,7 +880,7 @@ void dvb_ca_en50221_frda_irq(struct dvb_ca_en50221 *pubca, int slot) case DVB_CA_SLOTSTATE_RUNNING: if (ca->open) - dvb_ca_en50221_read_data(ca, slot, NULL, 0); + dvb_ca_en50221_thread_wakeup(ca); break; } } @@ -1126,16 +1114,16 @@ static int dvb_ca_en50221_thread(void *data) break; } - rxbuf = vmalloc(RX_BUFFER_SIZE); - if (rxbuf == NULL) { - printk("dvb_ca adapter %d: Unable to allocate CAM rx buffer :(\n", ca->dvbdev->adapter->num); - ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; - dvb_ca_en50221_thread_update_delay(ca); - break; + if (ca->slot_info[slot].rx_buffer.data == NULL) { + rxbuf = vmalloc(RX_BUFFER_SIZE); + if (rxbuf == NULL) { + printk("dvb_ca adapter %d: Unable to allocate CAM rx buffer :(\n", ca->dvbdev->adapter->num); + ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; + dvb_ca_en50221_thread_update_delay(ca); + break; + } + dvb_ringbuffer_init(&ca->slot_info[slot].rx_buffer, rxbuf, RX_BUFFER_SIZE); } - down_write(&ca->slot_info[slot].sem); - dvb_ringbuffer_init(&ca->slot_info[slot].rx_buffer, rxbuf, RX_BUFFER_SIZE); - up_write(&ca->slot_info[slot].sem); ca->pub->slot_ts_enable(ca->pub, slot); ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_RUNNING; @@ -1147,11 +1135,7 @@ static int dvb_ca_en50221_thread(void *data) if (!ca->open) continue; - // no need to poll if the CAM supports IRQs - if (ca->slot_info[slot].da_irq_supported) - break; - - // poll mode + // poll slots for data pktcount = 0; while ((status = dvb_ca_en50221_read_data(ca, slot, NULL, 0)) > 0) { if (!ca->open) @@ -1366,12 +1350,13 @@ exit: /** * Condition for waking up in dvb_ca_en50221_io_read_condition */ -static int dvb_ca_en50221_io_read_condition(struct dvb_ca_private *ca, int *result, int *_slot) +static int dvb_ca_en50221_io_read_condition(struct dvb_ca_private *ca, + int *result, int *_slot) { int slot; int slot_count = 0; int idx; - int fraglen; + size_t fraglen; int connection_id = -1; int found = 0; u8 hdr[2]; @@ -1381,10 +1366,7 @@ static int dvb_ca_en50221_io_read_condition(struct dvb_ca_private *ca, int *resu if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING) goto nextslot; - down_read(&ca->slot_info[slot].sem); - if (ca->slot_info[slot].rx_buffer.data == NULL) { - up_read(&ca->slot_info[slot].sem); return 0; } @@ -1402,10 +1384,7 @@ static int dvb_ca_en50221_io_read_condition(struct dvb_ca_private *ca, int *resu idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, idx, &fraglen); } - if (!found) - up_read(&ca->slot_info[slot].sem); - - nextslot: +nextslot: slot = (slot + 1) % ca->slot_count; slot_count++; } @@ -1510,8 +1489,7 @@ static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user * buf, goto exit; status = pktlen; - exit: - up_read(&ca->slot_info[slot].sem); +exit: return status; } @@ -1543,11 +1521,11 @@ static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file) for (i = 0; i < ca->slot_count; i++) { if (ca->slot_info[i].slot_state == DVB_CA_SLOTSTATE_RUNNING) { - down_write(&ca->slot_info[i].sem); if (ca->slot_info[i].rx_buffer.data != NULL) { + /* it is safe to call this here without locks because + * ca->open == 0. Data is not read in this case */ dvb_ringbuffer_flush(&ca->slot_info[i].rx_buffer); } - up_write(&ca->slot_info[i].sem); } } @@ -1606,7 +1584,6 @@ static unsigned int dvb_ca_en50221_io_poll(struct file *file, poll_table * wait) dprintk("%s\n", __FUNCTION__); if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1) { - up_read(&ca->slot_info[slot].sem); mask |= POLLIN; } @@ -1618,7 +1595,6 @@ static unsigned int dvb_ca_en50221_io_poll(struct file *file, poll_table * wait) poll_wait(file, &ca->wait_queue, wait); if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1) { - up_read(&ca->slot_info[slot].sem); mask |= POLLIN; } @@ -1708,7 +1684,6 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, ca->slot_info[i].slot_state = DVB_CA_SLOTSTATE_NONE; atomic_set(&ca->slot_info[i].camchange_count, 0); ca->slot_info[i].camchange_type = DVB_CA_EN50221_CAMCHANGE_REMOVED; - init_rwsem(&ca->slot_info[i].sem); } if (signal_pending(current)) { @@ -1728,7 +1703,7 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, ca->thread_pid = ret; return 0; - error: +error: if (ca != NULL) { if (ca->dvbdev != NULL) dvb_unregister_device(ca->dvbdev); @@ -1770,6 +1745,9 @@ void dvb_ca_en50221_release(struct dvb_ca_en50221 *pubca) for (i = 0; i < ca->slot_count; i++) { dvb_ca_en50221_slot_shutdown(ca, i); + if (ca->slot_info[i].rx_buffer.data != NULL) { + vfree(ca->slot_info[i].rx_buffer.data); + } } kfree(ca->slot_info); dvb_unregister_device(ca->dvbdev); diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c index dc476dda2b71..b4c899b15959 100644 --- a/drivers/media/dvb/dvb-core/dvb_demux.c +++ b/drivers/media/dvb/dvb-core/dvb_demux.c @@ -246,7 +246,7 @@ static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed, for (n = 0; sec->secbufp + 2 < limit; n++) { seclen = section_length(sec->secbuf); - if (seclen <= 0 || seclen > DMX_MAX_SECFEED_SIZE + if (seclen <= 0 || seclen > DMX_MAX_SECTION_SIZE || seclen + sec->secbufp > limit) return 0; sec->seclen = seclen; diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index a8bc84240b50..6ffa6b216363 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -42,8 +42,6 @@ #include "dvb_frontend.h" #include "dvbdev.h" -// #define DEBUG_LOCKLOSS 1 - static int dvb_frontend_debug; static int dvb_shutdown_timeout = 5; static int dvb_force_auto_inversion; @@ -438,25 +436,6 @@ static int dvb_frontend_thread(void *data) if (s & FE_HAS_LOCK) continue; else { /* if we _WERE_ tuned, but now don't have a lock */ -#ifdef DEBUG_LOCKLOSS - /* first of all try setting the tone again if it was on - this - * sometimes works around problems with noisy power supplies */ - if (fe->ops->set_tone && (fepriv->tone == SEC_TONE_ON)) { - fe->ops->set_tone(fe, fepriv->tone); - mdelay(100); - s = 0; - fe->ops->read_status(fe, &s); - if (s & FE_HAS_LOCK) { - printk("DVB%i: Lock was lost, but regained by setting " - "the tone. This may indicate your power supply " - "is noisy/slightly incompatable with this DVB-S " - "adapter\n", fe->dvb->num); - fepriv->state = FESTATE_TUNED; - continue; - } - } -#endif - /* some other reason for losing the lock - start zigzagging */ fepriv->state = FESTATE_ZIGZAG_FAST; fepriv->started_auto_step = fepriv->auto_step; check_wrapped = 0; @@ -577,6 +556,49 @@ static void dvb_frontend_stop(struct dvb_frontend *fe) fepriv->thread_pid); } +s32 timeval_usec_diff(struct timeval lasttime, struct timeval curtime) +{ + return ((curtime.tv_usec < lasttime.tv_usec) ? + 1000000 - lasttime.tv_usec + curtime.tv_usec : + curtime.tv_usec - lasttime.tv_usec); +} +EXPORT_SYMBOL(timeval_usec_diff); + +static inline void timeval_usec_add(struct timeval *curtime, u32 add_usec) +{ + curtime->tv_usec += add_usec; + if (curtime->tv_usec >= 1000000) { + curtime->tv_usec -= 1000000; + curtime->tv_sec++; + } +} + +/* + * Sleep until gettimeofday() > waketime + add_usec + * This needs to be as precise as possible, but as the delay is + * usually between 2ms and 32ms, it is done using a scheduled msleep + * followed by usleep (normally a busy-wait loop) for the remainder + */ +void dvb_frontend_sleep_until(struct timeval *waketime, u32 add_usec) +{ + struct timeval lasttime; + s32 delta, newdelta; + + timeval_usec_add(waketime, add_usec); + + do_gettimeofday(&lasttime); + delta = timeval_usec_diff(lasttime, *waketime); + if (delta > 2500) { + msleep((delta - 1500) / 1000); + do_gettimeofday(&lasttime); + newdelta = timeval_usec_diff(lasttime, *waketime); + delta = (newdelta > delta) ? 0 : newdelta; + } + if (delta > 0) + udelay(delta); +} +EXPORT_SYMBOL(dvb_frontend_sleep_until); + static int dvb_frontend_start(struct dvb_frontend *fe) { int ret; @@ -728,6 +750,60 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, err = fe->ops->dishnetwork_send_legacy_command(fe, (unsigned int) parg); fepriv->state = FESTATE_DISEQC; fepriv->status = 0; + } else if (fe->ops->set_voltage) { + /* + * NOTE: This is a fallback condition. Some frontends + * (stv0299 for instance) take longer than 8msec to + * respond to a set_voltage command. Those switches + * need custom routines to switch properly. For all + * other frontends, the following shoule work ok. + * Dish network legacy switches (as used by Dish500) + * are controlled by sending 9-bit command words + * spaced 8msec apart. + * the actual command word is switch/port dependant + * so it is up to the userspace application to send + * the right command. + * The command must always start with a '0' after + * initialization, so parg is 8 bits and does not + * include the initialization or start bit + */ + unsigned int cmd = ((unsigned int) parg) << 1; + struct timeval nexttime; + struct timeval tv[10]; + int i; + u8 last = 1; + if (dvb_frontend_debug) + printk("%s switch command: 0x%04x\n", __FUNCTION__, cmd); + do_gettimeofday(&nexttime); + if (dvb_frontend_debug) + memcpy(&tv[0], &nexttime, sizeof(struct timeval)); + /* before sending a command, initialize by sending + * a 32ms 18V to the switch + */ + fe->ops->set_voltage(fe, SEC_VOLTAGE_18); + dvb_frontend_sleep_until(&nexttime, 32000); + + for (i = 0; i < 9; i++) { + if (dvb_frontend_debug) + do_gettimeofday(&tv[i + 1]); + if ((cmd & 0x01) != last) { + /* set voltage to (last ? 13V : 18V) */ + fe->ops->set_voltage(fe, (last) ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18); + last = (last) ? 0 : 1; + } + cmd = cmd >> 1; + if (i != 8) + dvb_frontend_sleep_until(&nexttime, 8000); + } + if (dvb_frontend_debug) { + printk("%s(%d): switch delay (should be 32k followed by all 8k\n", + __FUNCTION__, fe->dvb->num); + for (i = 1; i < 10; i++) + printk("%d: %d\n", i, timeval_usec_diff(tv[i-1] , tv[i])); + } + err = 0; + fepriv->state = FESTATE_DISEQC; + fepriv->status = 0; } break; diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h index 9c2c1d1136bd..348c9b0b988a 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb/dvb-core/dvb_frontend.h @@ -101,4 +101,7 @@ extern int dvb_register_frontend(struct dvb_adapter* dvb, extern int dvb_unregister_frontend(struct dvb_frontend* fe); +extern void dvb_frontend_sleep_until(struct timeval *waketime, u32 add_usec); +extern s32 timeval_usec_diff(struct timeval lasttime, struct timeval curtime); + #endif diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c index 87935490bfb2..df536bd2e103 100644 --- a/drivers/media/dvb/dvb-core/dvb_net.c +++ b/drivers/media/dvb/dvb-core/dvb_net.c @@ -151,6 +151,8 @@ struct dvb_net_priv { unsigned char ule_bridged; /* Whether the ULE_BRIDGED extension header was found. */ int ule_sndu_remain; /* Nr. of bytes still required for current ULE SNDU. */ unsigned long ts_count; /* Current ts cell counter. */ + + struct semaphore mutex; }; @@ -881,12 +883,13 @@ static int dvb_net_filter_sec_set(struct net_device *dev, static int dvb_net_feed_start(struct net_device *dev) { - int ret, i; + int ret = 0, i; struct dvb_net_priv *priv = dev->priv; struct dmx_demux *demux = priv->demux; unsigned char *mac = (unsigned char *) dev->dev_addr; dprintk("%s: rx_mode %i\n", __FUNCTION__, priv->rx_mode); + down(&priv->mutex); if (priv->tsfeed || priv->secfeed || priv->secfilter || priv->multi_secfilter[0]) printk("%s: BUG %d\n", __FUNCTION__, __LINE__); @@ -900,7 +903,7 @@ static int dvb_net_feed_start(struct net_device *dev) dvb_net_sec_callback); if (ret<0) { printk("%s: could not allocate section feed\n", dev->name); - return ret; + goto error; } ret = priv->secfeed->set(priv->secfeed, priv->pid, 32768, 1); @@ -909,7 +912,7 @@ static int dvb_net_feed_start(struct net_device *dev) printk("%s: could not set section feed\n", dev->name); priv->demux->release_section_feed(priv->demux, priv->secfeed); priv->secfeed=NULL; - return ret; + goto error; } if (priv->rx_mode != RX_MODE_PROMISC) { @@ -948,7 +951,7 @@ static int dvb_net_feed_start(struct net_device *dev) ret = demux->allocate_ts_feed(demux, &priv->tsfeed, dvb_net_ts_callback); if (ret < 0) { printk("%s: could not allocate ts feed\n", dev->name); - return ret; + goto error; } /* Set netdevice pointer for ts decaps callback. */ @@ -962,23 +965,26 @@ static int dvb_net_feed_start(struct net_device *dev) printk("%s: could not set ts feed\n", dev->name); priv->demux->release_ts_feed(priv->demux, priv->tsfeed); priv->tsfeed = NULL; - return ret; + goto error; } dprintk("%s: start filtering\n", __FUNCTION__); priv->tsfeed->start_filtering(priv->tsfeed); } else - return -EINVAL; + ret = -EINVAL; - return 0; +error: + up(&priv->mutex); + return ret; } static int dvb_net_feed_stop(struct net_device *dev) { struct dvb_net_priv *priv = dev->priv; - int i; + int i, ret = 0; dprintk("%s\n", __FUNCTION__); + down(&priv->mutex); if (priv->feedtype == DVB_NET_FEEDTYPE_MPE) { if (priv->secfeed) { if (priv->secfeed->is_filtering) { @@ -1019,8 +1025,9 @@ static int dvb_net_feed_stop(struct net_device *dev) else printk("%s: no ts feed to stop\n", dev->name); } else - return -EINVAL; - return 0; + ret = -EINVAL; + up(&priv->mutex); + return ret; } @@ -1044,8 +1051,8 @@ static void wq_set_multicast_list (void *data) struct dvb_net_priv *priv = dev->priv; dvb_net_feed_stop(dev); - priv->rx_mode = RX_MODE_UNI; + spin_lock_bh(&dev->xmit_lock); if (dev->flags & IFF_PROMISC) { dprintk("%s: promiscuous mode\n", dev->name); @@ -1070,6 +1077,7 @@ static void wq_set_multicast_list (void *data) } } + spin_unlock_bh(&dev->xmit_lock); dvb_net_feed_start(dev); } @@ -1200,6 +1208,7 @@ static int dvb_net_add_if(struct dvb_net *dvbnet, u16 pid, u8 feedtype) INIT_WORK(&priv->set_multicast_list_wq, wq_set_multicast_list, net); INIT_WORK(&priv->restart_net_feed_wq, wq_restart_net_feed, net); + init_MUTEX(&priv->mutex); net->base_addr = pid; diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c index 4b7adca3e286..477b4fa56430 100644 --- a/drivers/media/dvb/dvb-core/dvbdev.c +++ b/drivers/media/dvb/dvb-core/dvbdev.c @@ -235,7 +235,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, S_IFCHR | S_IRUSR | S_IWUSR, "dvb/adapter%d/%s%d", adap->num, dnames[type], id); - class_device_create(dvb_class, MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)), + class_device_create(dvb_class, NULL, MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)), NULL, "dvb%d.%s%d", adap->num, dnames[type], id); dprintk("DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n", diff --git a/drivers/media/dvb/dvb-usb/a800.c b/drivers/media/dvb/dvb-usb/a800.c index e55322ef76b3..8c7beffb045f 100644 --- a/drivers/media/dvb/dvb-usb/a800.c +++ b/drivers/media/dvb/dvb-usb/a800.c @@ -43,11 +43,9 @@ static struct dvb_usb_rc_key a800_rc_keys[] = { { 0x02, 0x13, KEY_RIGHT }, /* R / CH RTN */ { 0x02, 0x17, KEY_PROG2 }, /* SNAP SHOT */ { 0x02, 0x10, KEY_PROG3 }, /* 16-CH PREV */ - { 0x02, 0x03, KEY_CHANNELUP }, /* CH UP */ { 0x02, 0x1e, KEY_VOLUMEDOWN }, /* VOL DOWN */ { 0x02, 0x0c, KEY_ZOOM }, /* FULL SCREEN */ { 0x02, 0x1f, KEY_VOLUMEUP }, /* VOL UP */ - { 0x02, 0x02, KEY_CHANNELDOWN }, /* CH DOWN */ { 0x02, 0x14, KEY_MUTE }, /* MUTE */ { 0x02, 0x08, KEY_AUDIO }, /* AUDIO */ { 0x02, 0x19, KEY_RECORD }, /* RECORD */ @@ -57,8 +55,6 @@ static struct dvb_usb_rc_key a800_rc_keys[] = { { 0x02, 0x1d, KEY_BACK }, /* << / RED */ { 0x02, 0x1c, KEY_FORWARD }, /* >> / YELLOW */ { 0x02, 0x03, KEY_TEXT }, /* TELETEXT */ - { 0x02, 0x01, KEY_FIRST }, /* |<< / GREEN */ - { 0x02, 0x00, KEY_LAST }, /* >>| / BLUE */ { 0x02, 0x04, KEY_EPG }, /* EPG */ { 0x02, 0x15, KEY_MENU }, /* MENU */ @@ -69,7 +65,7 @@ static struct dvb_usb_rc_key a800_rc_keys[] = { }; -int a800_rc_query(struct dvb_usb_device *d, u32 *event, int *state) +static int a800_rc_query(struct dvb_usb_device *d, u32 *event, int *state) { u8 key[5]; if (usb_control_msg(d->udev,usb_rcvctrlpipe(d->udev,0), diff --git a/drivers/media/dvb/dvb-usb/dibusb-common.c b/drivers/media/dvb/dvb-usb/dibusb-common.c index 00b946419b40..269d899da488 100644 --- a/drivers/media/dvb/dvb-usb/dibusb-common.c +++ b/drivers/media/dvb/dvb-usb/dibusb-common.c @@ -21,9 +21,9 @@ MODULE_LICENSE("GPL"); int dibusb_streaming_ctrl(struct dvb_usb_device *d, int onoff) { if (d->priv != NULL) { - struct dib_fe_xfer_ops *ops = d->priv; - if (ops->fifo_ctrl != NULL) - if (ops->fifo_ctrl(d->fe,onoff)) { + struct dibusb_state *st = d->priv; + if (st->ops.fifo_ctrl != NULL) + if (st->ops.fifo_ctrl(d->fe,onoff)) { err("error while controlling the fifo of the demod."); return -ENODEV; } @@ -35,9 +35,9 @@ EXPORT_SYMBOL(dibusb_streaming_ctrl); int dibusb_pid_filter(struct dvb_usb_device *d, int index, u16 pid, int onoff) { if (d->priv != NULL) { - struct dib_fe_xfer_ops *ops = d->priv; - if (d->pid_filtering && ops->pid_ctrl != NULL) - ops->pid_ctrl(d->fe,index,pid,onoff); + struct dibusb_state *st = d->priv; + if (st->ops.pid_ctrl != NULL) + st->ops.pid_ctrl(d->fe,index,pid,onoff); } return 0; } @@ -46,9 +46,9 @@ EXPORT_SYMBOL(dibusb_pid_filter); int dibusb_pid_filter_ctrl(struct dvb_usb_device *d, int onoff) { if (d->priv != NULL) { - struct dib_fe_xfer_ops *ops = d->priv; - if (ops->pid_parse != NULL) - if (ops->pid_parse(d->fe,onoff) < 0) + struct dibusb_state *st = d->priv; + if (st->ops.pid_parse != NULL) + if (st->ops.pid_parse(d->fe,onoff) < 0) err("could not handle pid_parser"); } return 0; diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/dvb/dvb-usb/dibusb-mb.c index 0058505634a0..aa271a2496d5 100644 --- a/drivers/media/dvb/dvb-usb/dibusb-mb.c +++ b/drivers/media/dvb/dvb-usb/dibusb-mb.c @@ -82,13 +82,15 @@ static int dibusb_tuner_probe_and_attach(struct dvb_usb_device *d) static struct dvb_usb_properties dibusb1_1_properties; static struct dvb_usb_properties dibusb1_1_an2235_properties; static struct dvb_usb_properties dibusb2_0b_properties; +static struct dvb_usb_properties artec_t1_usb2_properties; static int dibusb_probe(struct usb_interface *intf, const struct usb_device_id *id) { if (dvb_usb_device_init(intf,&dibusb1_1_properties,THIS_MODULE,NULL) == 0 || dvb_usb_device_init(intf,&dibusb1_1_an2235_properties,THIS_MODULE,NULL) == 0 || - dvb_usb_device_init(intf,&dibusb2_0b_properties,THIS_MODULE,NULL) == 0) + dvb_usb_device_init(intf,&dibusb2_0b_properties,THIS_MODULE,NULL) == 0 || + dvb_usb_device_init(intf,&artec_t1_usb2_properties,THIS_MODULE,NULL) == 0) return 0; return -EINVAL; @@ -128,10 +130,13 @@ static struct usb_device_id dibusb_dib3000mb_table [] = { /* 27 */ { USB_DEVICE(USB_VID_KWORLD, USB_PID_KWORLD_VSTREAM_COLD) }, +/* 28 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_COLD) }, +/* 29 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_WARM) }, + // #define DVB_USB_DIBUSB_MB_FAULTY_USB_IDs #ifdef DVB_USB_DIBUSB_MB_FAULTY_USB_IDs -/* 28 */ { USB_DEVICE(USB_VID_ANCHOR, USB_PID_ULTIMA_TVBOX_ANCHOR_COLD) }, +/* 30 */ { USB_DEVICE(USB_VID_ANCHOR, USB_PID_ULTIMA_TVBOX_ANCHOR_COLD) }, #endif { } /* Terminating entry */ }; @@ -264,7 +269,7 @@ static struct dvb_usb_properties dibusb1_1_an2235_properties = { }, #ifdef DVB_USB_DIBUSB_MB_FAULTY_USB_IDs { "Artec T1 USB1.1 TVBOX with AN2235 (faulty USB IDs)", - { &dibusb_dib3000mb_table[28], NULL }, + { &dibusb_dib3000mb_table[30], NULL }, { NULL }, }, #endif @@ -273,7 +278,7 @@ static struct dvb_usb_properties dibusb1_1_an2235_properties = { static struct dvb_usb_properties dibusb2_0b_properties = { .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_IS_AN_I2C_ADAPTER, - .pid_filter_count = 32, + .pid_filter_count = 16, .usb_ctrl = CYPRESS_FX2, @@ -321,6 +326,52 @@ static struct dvb_usb_properties dibusb2_0b_properties = { } }; +static struct dvb_usb_properties artec_t1_usb2_properties = { + .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_IS_AN_I2C_ADAPTER, + .pid_filter_count = 16, + + .usb_ctrl = CYPRESS_FX2, + + .firmware = "dvb-usb-dibusb-6.0.0.8.fw", + + .size_of_priv = sizeof(struct dibusb_state), + + .streaming_ctrl = dibusb2_0_streaming_ctrl, + .pid_filter = dibusb_pid_filter, + .pid_filter_ctrl = dibusb_pid_filter_ctrl, + .power_ctrl = dibusb2_0_power_ctrl, + .frontend_attach = dibusb_dib3000mb_frontend_attach, + .tuner_attach = dibusb_tuner_probe_and_attach, + + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_key_map = dibusb_rc_keys, + .rc_key_map_size = 63, /* wow, that is ugly ... I want to load it to the driver dynamically */ + .rc_query = dibusb_rc_query, + + .i2c_algo = &dibusb_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + /* parameter for the MPEG2-data transfer */ + .urb = { + .type = DVB_USB_BULK, + .count = 7, + .endpoint = 0x06, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + + .num_device_descs = 1, + .devices = { + { "Artec T1 USB2.0", + { &dibusb_dib3000mb_table[28], NULL }, + { &dibusb_dib3000mb_table[29], NULL }, + }, + } +}; + static struct usb_driver dibusb_driver = { .owner = THIS_MODULE, .name = "dvb_usb_dibusb_mb", diff --git a/drivers/media/dvb/dvb-usb/dibusb.h b/drivers/media/dvb/dvb-usb/dibusb.h index 6611f62977c0..2d99d05c7eab 100644 --- a/drivers/media/dvb/dvb-usb/dibusb.h +++ b/drivers/media/dvb/dvb-usb/dibusb.h @@ -11,7 +11,9 @@ #ifndef _DVB_USB_DIBUSB_H_ #define _DVB_USB_DIBUSB_H_ -#define DVB_USB_LOG_PREFIX "dibusb" +#ifndef DVB_USB_LOG_PREFIX + #define DVB_USB_LOG_PREFIX "dibusb" +#endif #include "dvb-usb.h" #include "dib3000.h" diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c index 74545f82eff1..f98e306a5759 100644 --- a/drivers/media/dvb/dvb-usb/digitv.c +++ b/drivers/media/dvb/dvb-usb/digitv.c @@ -148,7 +148,7 @@ static struct dvb_usb_rc_key digitv_rc_keys[] = { }; /* TODO is it really the NEC protocol ? */ -int digitv_rc_query(struct dvb_usb_device *d, u32 *event, int *state) +static int digitv_rc_query(struct dvb_usb_device *d, u32 *event, int *state) { u8 key[5]; diff --git a/drivers/media/dvb/dvb-usb/dtt200u.c b/drivers/media/dvb/dvb-usb/dtt200u.c index 5aa12ebab34f..b595476332cd 100644 --- a/drivers/media/dvb/dvb-usb/dtt200u.c +++ b/drivers/media/dvb/dvb-usb/dtt200u.c @@ -151,7 +151,7 @@ static struct dvb_usb_properties dtt200u_properties = { .cold_ids = { &dtt200u_usb_table[0], NULL }, .warm_ids = { &dtt200u_usb_table[1], NULL }, }, - { 0 }, + { NULL }, } }; @@ -192,7 +192,7 @@ static struct dvb_usb_properties wt220u_properties = { .cold_ids = { &dtt200u_usb_table[2], NULL }, .warm_ids = { &dtt200u_usb_table[3], NULL }, }, - { 0 }, + { NULL }, } }; diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 0818996bf150..6be99e537e12 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -43,10 +43,14 @@ #define USB_PID_COMPRO_DVBU2000_WARM 0xd001 #define USB_PID_COMPRO_DVBU2000_UNK_COLD 0x010c #define USB_PID_COMPRO_DVBU2000_UNK_WARM 0x010d +#define USB_PID_DIBCOM_HOOK_DEFAULT 0x0064 +#define USB_PID_DIBCOM_HOOK_DEFAULT_REENUM 0x0065 #define USB_PID_DIBCOM_MOD3000_COLD 0x0bb8 #define USB_PID_DIBCOM_MOD3000_WARM 0x0bb9 #define USB_PID_DIBCOM_MOD3001_COLD 0x0bc6 #define USB_PID_DIBCOM_MOD3001_WARM 0x0bc7 +#define USB_PID_DIBCOM_STK7700 0x1e14 +#define USB_PID_DIBCOM_STK7700_REENUM 0x1e15 #define USB_PID_DIBCOM_ANCHOR_2135_COLD 0x2131 #define USB_PID_GRANDTEC_DVBT_USB_COLD 0x0fa0 #define USB_PID_GRANDTEC_DVBT_USB_WARM 0x0fa1 @@ -68,6 +72,7 @@ #define USB_PID_ULTIMA_TVBOX_AN2235_WARM 0x8108 #define USB_PID_ULTIMA_TVBOX_ANCHOR_COLD 0x2235 #define USB_PID_ULTIMA_TVBOX_USB2_COLD 0x8109 +#define USB_PID_ULTIMA_TVBOX_USB2_WARM 0x810a #define USB_PID_ULTIMA_TVBOX_USB2_FX_COLD 0x8613 #define USB_PID_ULTIMA_TVBOX_USB2_FX_WARM 0x1002 #define USB_PID_UNK_HYPER_PALTEK_COLD 0x005e diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-init.c b/drivers/media/dvb/dvb-usb/dvb-usb-init.c index a902059812a2..dd8e0b94edba 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-init.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-init.c @@ -23,7 +23,7 @@ module_param_named(disable_rc_polling, dvb_usb_disable_rc_polling, int, 0644); MODULE_PARM_DESC(disable_rc_polling, "disable remote control polling (default: 0)."); /* general initialization functions */ -int dvb_usb_exit(struct dvb_usb_device *d) +static int dvb_usb_exit(struct dvb_usb_device *d) { deb_info("state before exiting everything: %x\n",d->state); dvb_usb_remote_exit(d); diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c index fc7800f1743e..e5c6d9835e06 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c @@ -39,9 +39,9 @@ static void dvb_usb_read_remote_control(void *data) d->last_event = event; case REMOTE_KEY_REPEAT: deb_rc("key repeated\n"); - input_event(&d->rc_input_dev, EV_KEY, d->last_event, 1); - input_event(&d->rc_input_dev, EV_KEY, d->last_event, 0); - input_sync(&d->rc_input_dev); + input_event(d->rc_input_dev, EV_KEY, event, 1); + input_event(d->rc_input_dev, EV_KEY, d->last_event, 0); + input_sync(d->rc_input_dev); break; default: break; @@ -53,8 +53,8 @@ static void dvb_usb_read_remote_control(void *data) deb_rc("NO KEY PRESSED\n"); if (d->last_state != REMOTE_NO_KEY_PRESSED) { deb_rc("releasing event %d\n",d->last_event); - input_event(&d->rc_input_dev, EV_KEY, d->last_event, 0); - input_sync(&d->rc_input_dev); + input_event(d->rc_input_dev, EV_KEY, d->last_event, 0); + input_sync(d->rc_input_dev); } d->last_state = REMOTE_NO_KEY_PRESSED; d->last_event = 0; @@ -63,8 +63,8 @@ static void dvb_usb_read_remote_control(void *data) deb_rc("KEY PRESSED\n"); deb_rc("pressing event %d\n",event); - input_event(&d->rc_input_dev, EV_KEY, event, 1); - input_sync(&d->rc_input_dev); + input_event(d->rc_input_dev, EV_KEY, event, 1); + input_sync(d->rc_input_dev); d->last_event = event; d->last_state = REMOTE_KEY_PRESSED; @@ -73,8 +73,8 @@ static void dvb_usb_read_remote_control(void *data) deb_rc("KEY_REPEAT\n"); if (d->last_state != REMOTE_NO_KEY_PRESSED) { deb_rc("repeating event %d\n",d->last_event); - input_event(&d->rc_input_dev, EV_KEY, d->last_event, 2); - input_sync(&d->rc_input_dev); + input_event(d->rc_input_dev, EV_KEY, d->last_event, 2); + input_sync(d->rc_input_dev); d->last_state = REMOTE_KEY_REPEAT; } default: @@ -89,24 +89,30 @@ schedule: int dvb_usb_remote_init(struct dvb_usb_device *d) { int i; + if (d->props.rc_key_map == NULL || d->props.rc_query == NULL || dvb_usb_disable_rc_polling) return 0; - /* Initialise the remote-control structures.*/ - init_input_dev(&d->rc_input_dev); + usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys)); + strlcpy(d->rc_phys, "/ir0", sizeof(d->rc_phys)); + + d->rc_input_dev = input_allocate_device(); + if (!d->rc_input_dev) + return -ENOMEM; - d->rc_input_dev.evbit[0] = BIT(EV_KEY); - d->rc_input_dev.keycodesize = sizeof(unsigned char); - d->rc_input_dev.keycodemax = KEY_MAX; - d->rc_input_dev.name = "IR-receiver inside an USB DVB receiver"; + d->rc_input_dev->evbit[0] = BIT(EV_KEY); + d->rc_input_dev->keycodesize = sizeof(unsigned char); + d->rc_input_dev->keycodemax = KEY_MAX; + d->rc_input_dev->name = "IR-receiver inside an USB DVB receiver"; + d->rc_input_dev->phys = d->rc_phys; /* set the bits for the keys */ - deb_rc("key map size: %d\n",d->props.rc_key_map_size); + deb_rc("key map size: %d\n", d->props.rc_key_map_size); for (i = 0; i < d->props.rc_key_map_size; i++) { deb_rc("setting bit for event %d item %d\n",d->props.rc_key_map[i].event, i); - set_bit(d->props.rc_key_map[i].event, d->rc_input_dev.keybit); + set_bit(d->props.rc_key_map[i].event, d->rc_input_dev->keybit); } /* Start the remote-control polling. */ @@ -114,14 +120,14 @@ int dvb_usb_remote_init(struct dvb_usb_device *d) d->props.rc_interval = 100; /* default */ /* setting these two values to non-zero, we have to manage key repeats */ - d->rc_input_dev.rep[REP_PERIOD] = d->props.rc_interval; - d->rc_input_dev.rep[REP_DELAY] = d->props.rc_interval + 150; + d->rc_input_dev->rep[REP_PERIOD] = d->props.rc_interval; + d->rc_input_dev->rep[REP_DELAY] = d->props.rc_interval + 150; - input_register_device(&d->rc_input_dev); + input_register_device(d->rc_input_dev); INIT_WORK(&d->rc_query_work, dvb_usb_read_remote_control, d); - info("schedule remote query interval to %d msecs.",d->props.rc_interval); + info("schedule remote query interval to %d msecs.", d->props.rc_interval); schedule_delayed_work(&d->rc_query_work,msecs_to_jiffies(d->props.rc_interval)); d->state |= DVB_USB_STATE_REMOTE; @@ -134,7 +140,7 @@ int dvb_usb_remote_exit(struct dvb_usb_device *d) if (d->state & DVB_USB_STATE_REMOTE) { cancel_delayed_work(&d->rc_query_work); flush_scheduled_work(); - input_unregister_device(&d->rc_input_dev); + input_unregister_device(d->rc_input_dev); } d->state &= ~DVB_USB_STATE_REMOTE; return 0; diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-urb.c b/drivers/media/dvb/dvb-usb/dvb-usb-urb.c index f5799a4c228e..36b7048c02d2 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-urb.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-urb.c @@ -196,7 +196,9 @@ static int dvb_usb_allocate_stream_buffers(struct dvb_usb_device *d, int num, un dvb_usb_free_stream_buffers(d); return -ENOMEM; } - deb_mem("buffer %d: %p (dma: %d)\n",d->buf_num,d->buf_list[d->buf_num],d->dma_addr[d->buf_num]); + deb_mem("buffer %d: %p (dma: %llu)\n", + d->buf_num, d->buf_list[d->buf_num], + (unsigned long long)d->dma_addr[d->buf_num]); memset(d->buf_list[d->buf_num],0,size); } deb_mem("allocation successful\n"); diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h index 0e4f1035b0dd..b4a1a98006c7 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb.h @@ -300,7 +300,8 @@ struct dvb_usb_device { int (*fe_init) (struct dvb_frontend *); /* remote control */ - struct input_dev rc_input_dev; + struct input_dev *rc_input_dev; + char rc_phys[64]; struct work_struct rc_query_work; u32 last_event; int last_state; diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c index 0f57abeb6d6b..75765e3a569c 100644 --- a/drivers/media/dvb/dvb-usb/vp7045.c +++ b/drivers/media/dvb/dvb-usb/vp7045.c @@ -247,7 +247,7 @@ static struct dvb_usb_properties vp7045_properties = { .cold_ids = { &vp7045_usb_table[2], NULL }, .warm_ids = { &vp7045_usb_table[3], NULL }, }, - { 0 }, + { NULL }, } }; diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index a50a41f6f79d..8e269e1c1f9d 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -164,6 +164,14 @@ config DVB_NXT2002 help An ATSC 8VSB tuner module. Say Y when you want to support this frontend. +config DVB_NXT200X + tristate "Nextwave NXT2002/NXT2004 based" + depends on DVB_CORE + select FW_LOADER + help + An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want + to support this frontend. + config DVB_OR51211 tristate "or51211 based (pcHDTV HD2000 card)" depends on DVB_CORE diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index ad8658ffd60a..a98760fe08a1 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_DVB_TDA80XX) += tda80xx.o obj-$(CONFIG_DVB_TDA10021) += tda10021.o obj-$(CONFIG_DVB_STV0297) += stv0297.o obj-$(CONFIG_DVB_NXT2002) += nxt2002.o +obj-$(CONFIG_DVB_NXT200X) += nxt200x.o obj-$(CONFIG_DVB_OR51211) += or51211.o obj-$(CONFIG_DVB_OR51132) += or51132.o obj-$(CONFIG_DVB_BCM3510) += bcm3510.o diff --git a/drivers/media/dvb/frontends/bcm3510.c b/drivers/media/dvb/frontends/bcm3510.c index f5fdc5c3e605..f6d4ee78bdd4 100644 --- a/drivers/media/dvb/frontends/bcm3510.c +++ b/drivers/media/dvb/frontends/bcm3510.c @@ -36,6 +36,9 @@ #include <linux/moduleparam.h> #include <linux/device.h> #include <linux/firmware.h> +#include <linux/jiffies.h> +#include <linux/string.h> +#include <linux/slab.h> #include "dvb_frontend.h" #include "bcm3510.h" diff --git a/drivers/media/dvb/frontends/cx22702.c b/drivers/media/dvb/frontends/cx22702.c index 9f639297a9f2..d9a8ede14b45 100644 --- a/drivers/media/dvb/frontends/cx22702.c +++ b/drivers/media/dvb/frontends/cx22702.c @@ -7,7 +7,7 @@ Copyright (C) 2001-2002 Convergence Integrated Media GmbH Holger Waechtler <holger@convergence.de> - Copyright (C) 2004 Steven Toth <steve@toth.demon.co.uk> + Copyright (C) 2004 Steven Toth <stoth@hauppauge.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 diff --git a/drivers/media/dvb/frontends/cx22702.h b/drivers/media/dvb/frontends/cx22702.h index 11f86806756e..1f250885d2ce 100644 --- a/drivers/media/dvb/frontends/cx22702.h +++ b/drivers/media/dvb/frontends/cx22702.h @@ -7,7 +7,7 @@ Copyright (C) 2001-2002 Convergence Integrated Media GmbH Holger Waechtler <holger@convergence.de> - Copyright (C) 2004 Steven Toth <steve@toth.demon.co.uk> + Copyright (C) 2004 Steven Toth <stoth@hauppauge.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 diff --git a/drivers/media/dvb/frontends/cx24110.c b/drivers/media/dvb/frontends/cx24110.c index d4b97989e3ed..654d7dc879d9 100644 --- a/drivers/media/dvb/frontends/cx24110.c +++ b/drivers/media/dvb/frontends/cx24110.c @@ -27,6 +27,7 @@ #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/init.h> +#include <linux/jiffies.h> #include "dvb_frontend.h" #include "cx24110.h" diff --git a/drivers/media/dvb/frontends/dib3000mb.c b/drivers/media/dvb/frontends/dib3000mb.c index 21433e1831e7..6b0553608610 100644 --- a/drivers/media/dvb/frontends/dib3000mb.c +++ b/drivers/media/dvb/frontends/dib3000mb.c @@ -27,6 +27,8 @@ #include <linux/moduleparam.h> #include <linux/init.h> #include <linux/delay.h> +#include <linux/string.h> +#include <linux/slab.h> #include "dib3000-common.h" #include "dib3000mb_priv.h" diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c index 441de665fec3..c024fad17337 100644 --- a/drivers/media/dvb/frontends/dib3000mc.c +++ b/drivers/media/dvb/frontends/dib3000mc.c @@ -26,6 +26,8 @@ #include <linux/moduleparam.h> #include <linux/init.h> #include <linux/delay.h> +#include <linux/string.h> +#include <linux/slab.h> #include "dib3000-common.h" #include "dib3000mc_priv.h" diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c index 536c35d969b7..f857b869616c 100644 --- a/drivers/media/dvb/frontends/dvb-pll.c +++ b/drivers/media/dvb/frontends/dvb-pll.c @@ -226,7 +226,7 @@ struct dvb_pll_desc dvb_pll_tua6034 = { EXPORT_SYMBOL(dvb_pll_tua6034); /* Infineon TUA6034 - * used in LG Innotek TDVS-H062F + * used in LG TDVS H061F and LG TDVS H062F */ struct dvb_pll_desc dvb_pll_tdvs_tua6034 = { .name = "LG/Infineon TUA6034", @@ -292,6 +292,58 @@ struct dvb_pll_desc dvb_pll_tded4 = { }; EXPORT_SYMBOL(dvb_pll_tded4); +/* ALPS TDHU2 + * used in AverTVHD MCE A180 + */ +struct dvb_pll_desc dvb_pll_tdhu2 = { + .name = "ALPS TDHU2", + .min = 54000000, + .max = 864000000, + .count = 4, + .entries = { + { 162000000, 44000000, 62500, 0x85, 0x01 }, + { 426000000, 44000000, 62500, 0x85, 0x02 }, + { 782000000, 44000000, 62500, 0x85, 0x08 }, + { 999999999, 44000000, 62500, 0x85, 0x88 }, + } +}; +EXPORT_SYMBOL(dvb_pll_tdhu2); + +/* Philips TUV1236D + * used in ATI HDTV Wonder + */ +struct dvb_pll_desc dvb_pll_tuv1236d = { + .name = "Philips TUV1236D", + .min = 54000000, + .max = 864000000, + .count = 3, + .entries = { + { 157250000, 44000000, 62500, 0xc6, 0x41 }, + { 454000000, 44000000, 62500, 0xc6, 0x42 }, + { 999999999, 44000000, 62500, 0xc6, 0x44 }, + }, +}; +EXPORT_SYMBOL(dvb_pll_tuv1236d); + +/* Samsung TBMV30111IN + * used in Air2PC ATSC - 2nd generation (nxt2002) + */ +struct dvb_pll_desc dvb_pll_tbmv30111in = { + .name = "Samsung TBMV30111IN", + .min = 54000000, + .max = 860000000, + .count = 4, + .entries = { + { 172000000, 44000000, 166666, 0xb4, 0x01 }, + { 214000000, 44000000, 166666, 0xb4, 0x02 }, + { 467000000, 44000000, 166666, 0xbc, 0x02 }, + { 721000000, 44000000, 166666, 0xbc, 0x08 }, + { 841000000, 44000000, 166666, 0xf4, 0x08 }, + { 999999999, 44000000, 166666, 0xfc, 0x02 }, + } +}; +EXPORT_SYMBOL(dvb_pll_tbmv30111in); + /* ----------------------------------------------------------- */ /* code */ diff --git a/drivers/media/dvb/frontends/dvb-pll.h b/drivers/media/dvb/frontends/dvb-pll.h index 205b2d1a8852..497d31dcf41e 100644 --- a/drivers/media/dvb/frontends/dvb-pll.h +++ b/drivers/media/dvb/frontends/dvb-pll.h @@ -36,6 +36,10 @@ extern struct dvb_pll_desc dvb_pll_tda665x; extern struct dvb_pll_desc dvb_pll_fmd1216me; extern struct dvb_pll_desc dvb_pll_tded4; +extern struct dvb_pll_desc dvb_pll_tuv1236d; +extern struct dvb_pll_desc dvb_pll_tdhu2; +extern struct dvb_pll_desc dvb_pll_tbmv30111in; + int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf, u32 freq, int bandwidth); diff --git a/drivers/media/dvb/frontends/dvb_dummy_fe.c b/drivers/media/dvb/frontends/dvb_dummy_fe.c index cff93b9d8ab2..645946a992d9 100644 --- a/drivers/media/dvb/frontends/dvb_dummy_fe.c +++ b/drivers/media/dvb/frontends/dvb_dummy_fe.c @@ -22,6 +22,8 @@ #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/init.h> +#include <linux/string.h> +#include <linux/slab.h> #include "dvb_frontend.h" #include "dvb_dummy_fe.h" @@ -146,7 +148,7 @@ struct dvb_frontend* dvb_dummy_fe_qpsk_attach() return &state->frontend; error: - if (state) kfree(state); + kfree(state); return NULL; } @@ -169,7 +171,7 @@ struct dvb_frontend* dvb_dummy_fe_qam_attach() return &state->frontend; error: - if (state) kfree(state); + kfree(state); return NULL; } diff --git a/drivers/media/dvb/frontends/l64781.c b/drivers/media/dvb/frontends/l64781.c index faaad1ae8559..19b4bf7c21a7 100644 --- a/drivers/media/dvb/frontends/l64781.c +++ b/drivers/media/dvb/frontends/l64781.c @@ -559,7 +559,8 @@ struct dvb_frontend* l64781_attach(const struct l64781_config* config, return &state->frontend; error: - if (reg0x3e >= 0) l64781_writereg (state, 0x3e, reg0x3e); /* restore reg 0x3e */ + if (reg0x3e >= 0) + l64781_writereg (state, 0x3e, reg0x3e); /* restore reg 0x3e */ kfree(state); return NULL; } diff --git a/drivers/media/dvb/frontends/lgdt330x.c b/drivers/media/dvb/frontends/lgdt330x.c index 7142b9c51dd2..6a33f5a19a8d 100644 --- a/drivers/media/dvb/frontends/lgdt330x.c +++ b/drivers/media/dvb/frontends/lgdt330x.c @@ -26,6 +26,8 @@ * DViCO FusionHDTV 3 Gold-Q * DViCO FusionHDTV 3 Gold-T * DViCO FusionHDTV 5 Gold + * DViCO FusionHDTV 5 Lite + * Air2PC/AirStar 2 ATSC 3rd generation (HD5000) * * TODO: * signal strength always returns 0. @@ -37,6 +39,8 @@ #include <linux/moduleparam.h> #include <linux/init.h> #include <linux/delay.h> +#include <linux/string.h> +#include <linux/slab.h> #include <asm/byteorder.h> #include "dvb_frontend.h" @@ -220,6 +224,11 @@ static int lgdt330x_init(struct dvb_frontend* fe) 0x4c, 0x14 }; + static u8 flip_lgdt3303_init_data[] = { + 0x4c, 0x14, + 0x87, 0xf3 + }; + struct lgdt330x_state* state = fe->demodulator_priv; char *chip_name; int err; @@ -232,8 +241,13 @@ static int lgdt330x_init(struct dvb_frontend* fe) break; case LGDT3303: chip_name = "LGDT3303"; - err = i2c_write_demod_bytes(state, lgdt3303_init_data, - sizeof(lgdt3303_init_data)); + if (state->config->clock_polarity_flip) { + err = i2c_write_demod_bytes(state, flip_lgdt3303_init_data, + sizeof(flip_lgdt3303_init_data)); + } else { + err = i2c_write_demod_bytes(state, lgdt3303_init_data, + sizeof(lgdt3303_init_data)); + } break; default: chip_name = "undefined"; @@ -729,8 +743,7 @@ struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config, return &state->frontend; error: - if (state) - kfree(state); + kfree(state); dprintk("%s: ERROR\n",__FUNCTION__); return NULL; } @@ -742,9 +755,8 @@ static struct dvb_frontend_ops lgdt3302_ops = { .frequency_min= 54000000, .frequency_max= 858000000, .frequency_stepsize= 62500, - /* Symbol rate is for all VSB modes need to check QAM */ - .symbol_rate_min = 10762000, - .symbol_rate_max = 10762000, + .symbol_rate_min = 5056941, /* QAM 64 */ + .symbol_rate_max = 10762000, /* VSB 8 */ .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB }, .init = lgdt330x_init, @@ -766,9 +778,8 @@ static struct dvb_frontend_ops lgdt3303_ops = { .frequency_min= 54000000, .frequency_max= 858000000, .frequency_stepsize= 62500, - /* Symbol rate is for all VSB modes need to check QAM */ - .symbol_rate_min = 10762000, - .symbol_rate_max = 10762000, + .symbol_rate_min = 5056941, /* QAM 64 */ + .symbol_rate_max = 10762000, /* VSB 8 */ .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB }, .init = lgdt330x_init, diff --git a/drivers/media/dvb/frontends/lgdt330x.h b/drivers/media/dvb/frontends/lgdt330x.h index e209ba1e47c5..2a6529cccf1a 100644 --- a/drivers/media/dvb/frontends/lgdt330x.h +++ b/drivers/media/dvb/frontends/lgdt330x.h @@ -47,6 +47,10 @@ struct lgdt330x_config /* Need to set device param for start_dma */ int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured); + + /* Flip the polarity of the mpeg data transfer clock using alternate init data + * This option applies ONLY to LGDT3303 - 0:disabled (default) 1:enabled */ + int clock_polarity_flip; }; extern struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config, diff --git a/drivers/media/dvb/frontends/mt312.c b/drivers/media/dvb/frontends/mt312.c index e455aecd76b2..9c67f406d581 100644 --- a/drivers/media/dvb/frontends/mt312.c +++ b/drivers/media/dvb/frontends/mt312.c @@ -29,6 +29,8 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/moduleparam.h> +#include <linux/string.h> +#include <linux/slab.h> #include "dvb_frontend.h" #include "mt312_priv.h" @@ -675,8 +677,7 @@ struct dvb_frontend* mt312_attach(const struct mt312_config* config, return &state->frontend; error: - if (state) - kfree(state); + kfree(state); return NULL; } diff --git a/drivers/media/dvb/frontends/mt352.c b/drivers/media/dvb/frontends/mt352.c index cc1bc0edd65e..f0c610f2c2df 100644 --- a/drivers/media/dvb/frontends/mt352.c +++ b/drivers/media/dvb/frontends/mt352.c @@ -35,6 +35,8 @@ #include <linux/moduleparam.h> #include <linux/init.h> #include <linux/delay.h> +#include <linux/string.h> +#include <linux/slab.h> #include "dvb_frontend.h" #include "mt352_priv.h" diff --git a/drivers/media/dvb/frontends/nxt2002.c b/drivers/media/dvb/frontends/nxt2002.c index 35a1d60f1927..30786b1911bd 100644 --- a/drivers/media/dvb/frontends/nxt2002.c +++ b/drivers/media/dvb/frontends/nxt2002.c @@ -32,6 +32,8 @@ #include <linux/moduleparam.h> #include <linux/device.h> #include <linux/firmware.h> +#include <linux/string.h> +#include <linux/slab.h> #include "dvb_frontend.h" #include "nxt2002.h" diff --git a/drivers/media/dvb/frontends/nxt200x.c b/drivers/media/dvb/frontends/nxt200x.c new file mode 100644 index 000000000000..84b62881cea7 --- /dev/null +++ b/drivers/media/dvb/frontends/nxt200x.c @@ -0,0 +1,1207 @@ +/* + * Support for NXT2002 and NXT2004 - VSB/QAM + * + * Copyright (C) 2005 Kirk Lapray (kirk.lapray@gmail.com) + * based on nxt2002 by Taylor Jacob <rtjacob@earthlink.net> + * and nxt2004 by Jean-Francois Thibert (jeanfrancois@sagetv.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. + * +*/ + +/* + * NOTES ABOUT THIS DRIVER + * + * This Linux driver supports: + * B2C2/BBTI Technisat Air2PC - ATSC (NXT2002) + * AverTVHD MCE A180 (NXT2004) + * ATI HDTV Wonder (NXT2004) + * + * This driver needs external firmware. Please use the command + * "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2002" or + * "<kerneldir>/Documentation/dvb/get_dvb_firmware nxt2004" to + * download/extract the appropriate firmware, and then copy it to + * /usr/lib/hotplug/firmware/ or /lib/firmware/ + * (depending on configuration of firmware hotplug). + */ +#define NXT2002_DEFAULT_FIRMWARE "dvb-fe-nxt2002.fw" +#define NXT2004_DEFAULT_FIRMWARE "dvb-fe-nxt2004.fw" +#define CRC_CCIT_MASK 0x1021 + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/slab.h> +#include <linux/string.h> + +#include "dvb_frontend.h" +#include "dvb-pll.h" +#include "nxt200x.h" + +struct nxt200x_state { + + struct i2c_adapter* i2c; + struct dvb_frontend_ops ops; + const struct nxt200x_config* config; + struct dvb_frontend frontend; + + /* demodulator private data */ + nxt_chip_type demod_chip; + u8 initialised:1; +}; + +static int debug; +#define dprintk(args...) \ + do { \ + if (debug) printk(KERN_DEBUG "nxt200x: " args); \ + } while (0) + +static int i2c_writebytes (struct nxt200x_state* state, u8 addr, u8 *buf, u8 len) +{ + int err; + struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = len }; + + if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) { + printk (KERN_WARNING "nxt200x: %s: i2c write error (addr 0x%02x, err == %i)\n", + __FUNCTION__, addr, err); + return -EREMOTEIO; + } + return 0; +} + +static u8 i2c_readbytes (struct nxt200x_state* state, u8 addr, u8* buf, u8 len) +{ + int err; + struct i2c_msg msg = { .addr = addr, .flags = I2C_M_RD, .buf = buf, .len = len }; + + if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) { + printk (KERN_WARNING "nxt200x: %s: i2c read error (addr 0x%02x, err == %i)\n", + __FUNCTION__, addr, err); + return -EREMOTEIO; + } + return 0; +} + +static int nxt200x_writebytes (struct nxt200x_state* state, u8 reg, u8 *buf, u8 len) +{ + u8 buf2 [len+1]; + int err; + struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf2, .len = len + 1 }; + + buf2[0] = reg; + memcpy(&buf2[1], buf, len); + + if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) { + printk (KERN_WARNING "nxt200x: %s: i2c write error (addr 0x%02x, err == %i)\n", + __FUNCTION__, state->config->demod_address, err); + return -EREMOTEIO; + } + return 0; +} + +static u8 nxt200x_readbytes (struct nxt200x_state* state, u8 reg, u8* buf, u8 len) +{ + u8 reg2 [] = { reg }; + + struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = reg2, .len = 1 }, + { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = buf, .len = len } }; + + int err; + + if ((err = i2c_transfer (state->i2c, msg, 2)) != 2) { + printk (KERN_WARNING "nxt200x: %s: i2c read error (addr 0x%02x, err == %i)\n", + __FUNCTION__, state->config->demod_address, err); + return -EREMOTEIO; + } + return 0; +} + +static u16 nxt200x_crc(u16 crc, u8 c) +{ + u8 i; + u16 input = (u16) c & 0xFF; + + input<<=8; + for(i=0; i<8; i++) { + if((crc^input) & 0x8000) + crc=(crc<<1)^CRC_CCIT_MASK; + else + crc<<=1; + input<<=1; + } + return crc; +} + +static int nxt200x_writereg_multibyte (struct nxt200x_state* state, u8 reg, u8* data, u8 len) +{ + u8 attr, len2, buf; + dprintk("%s\n", __FUNCTION__); + + /* set mutli register register */ + nxt200x_writebytes(state, 0x35, ®, 1); + + /* send the actual data */ + nxt200x_writebytes(state, 0x36, data, len); + + switch (state->demod_chip) { + case NXT2002: + len2 = len; + buf = 0x02; + break; + case NXT2004: + /* probably not right, but gives correct values */ + attr = 0x02; + if (reg & 0x80) { + attr = attr << 1; + if (reg & 0x04) + attr = attr >> 1; + } + /* set write bit */ + len2 = ((attr << 4) | 0x10) | len; + buf = 0x80; + break; + default: + return -EINVAL; + break; + } + + /* set multi register length */ + nxt200x_writebytes(state, 0x34, &len2, 1); + + /* toggle the multireg write bit */ + nxt200x_writebytes(state, 0x21, &buf, 1); + + nxt200x_readbytes(state, 0x21, &buf, 1); + + switch (state->demod_chip) { + case NXT2002: + if ((buf & 0x02) == 0) + return 0; + break; + case NXT2004: + if (buf == 0) + return 0; + break; + default: + return -EINVAL; + break; + } + + printk(KERN_WARNING "nxt200x: Error writing multireg register 0x%02X\n",reg); + + return 0; +} + +static int nxt200x_readreg_multibyte (struct nxt200x_state* state, u8 reg, u8* data, u8 len) +{ + int i; + u8 buf, len2, attr; + dprintk("%s\n", __FUNCTION__); + + /* set mutli register register */ + nxt200x_writebytes(state, 0x35, ®, 1); + + switch (state->demod_chip) { + case NXT2002: + /* set multi register length */ + len2 = len & 0x80; + nxt200x_writebytes(state, 0x34, &len2, 1); + + /* read the actual data */ + nxt200x_readbytes(state, reg, data, len); + return 0; + break; + case NXT2004: + /* probably not right, but gives correct values */ + attr = 0x02; + if (reg & 0x80) { + attr = attr << 1; + if (reg & 0x04) + attr = attr >> 1; + } + + /* set multi register length */ + len2 = (attr << 4) | len; + nxt200x_writebytes(state, 0x34, &len2, 1); + + /* toggle the multireg bit*/ + buf = 0x80; + nxt200x_writebytes(state, 0x21, &buf, 1); + + /* read the actual data */ + for(i = 0; i < len; i++) { + nxt200x_readbytes(state, 0x36 + i, &data[i], 1); + } + return 0; + break; + default: + return -EINVAL; + break; + } +} + +static void nxt200x_microcontroller_stop (struct nxt200x_state* state) +{ + u8 buf, stopval, counter = 0; + dprintk("%s\n", __FUNCTION__); + + /* set correct stop value */ + switch (state->demod_chip) { + case NXT2002: + stopval = 0x40; + break; + case NXT2004: + stopval = 0x10; + break; + default: + stopval = 0; + break; + } + + buf = 0x80; + nxt200x_writebytes(state, 0x22, &buf, 1); + + while (counter < 20) { + nxt200x_readbytes(state, 0x31, &buf, 1); + if (buf & stopval) + return; + msleep(10); + counter++; + } + + printk(KERN_WARNING "nxt200x: Timeout waiting for nxt200x to stop. This is ok after firmware upload.\n"); + return; +} + +static void nxt200x_microcontroller_start (struct nxt200x_state* state) +{ + u8 buf; + dprintk("%s\n", __FUNCTION__); + + buf = 0x00; + nxt200x_writebytes(state, 0x22, &buf, 1); +} + +static void nxt2004_microcontroller_init (struct nxt200x_state* state) +{ + u8 buf[9]; + u8 counter = 0; + dprintk("%s\n", __FUNCTION__); + + buf[0] = 0x00; + nxt200x_writebytes(state, 0x2b, buf, 1); + buf[0] = 0x70; + nxt200x_writebytes(state, 0x34, buf, 1); + buf[0] = 0x04; + nxt200x_writebytes(state, 0x35, buf, 1); + buf[0] = 0x01; buf[1] = 0x23; buf[2] = 0x45; buf[3] = 0x67; buf[4] = 0x89; + buf[5] = 0xAB; buf[6] = 0xCD; buf[7] = 0xEF; buf[8] = 0xC0; + nxt200x_writebytes(state, 0x36, buf, 9); + buf[0] = 0x80; + nxt200x_writebytes(state, 0x21, buf, 1); + + while (counter < 20) { + nxt200x_readbytes(state, 0x21, buf, 1); + if (buf[0] == 0) + return; + msleep(10); + counter++; + } + + printk(KERN_WARNING "nxt200x: Timeout waiting for nxt2004 to init.\n"); + + return; +} + +static int nxt200x_writetuner (struct nxt200x_state* state, u8* data) +{ + u8 buf, count = 0; + + dprintk("%s\n", __FUNCTION__); + + dprintk("Tuner Bytes: %02X %02X %02X %02X\n", data[0], data[1], data[2], data[3]); + + /* if NXT2004, write directly to tuner. if NXT2002, write through NXT chip. + * direct write is required for Philips TUV1236D and ALPS TDHU2 */ + switch (state->demod_chip) { + case NXT2004: + if (i2c_writebytes(state, state->config->pll_address, data, 4)) + printk(KERN_WARNING "nxt200x: error writing to tuner\n"); + /* wait until we have a lock */ + while (count < 20) { + i2c_readbytes(state, state->config->pll_address, &buf, 1); + if (buf & 0x40) + return 0; + msleep(100); + count++; + } + printk("nxt2004: timeout waiting for tuner lock\n"); + break; + case NXT2002: + /* set the i2c transfer speed to the tuner */ + buf = 0x03; + nxt200x_writebytes(state, 0x20, &buf, 1); + + /* setup to transfer 4 bytes via i2c */ + buf = 0x04; + nxt200x_writebytes(state, 0x34, &buf, 1); + + /* write actual tuner bytes */ + nxt200x_writebytes(state, 0x36, data, 4); + + /* set tuner i2c address */ + buf = state->config->pll_address; + nxt200x_writebytes(state, 0x35, &buf, 1); + + /* write UC Opmode to begin transfer */ + buf = 0x80; + nxt200x_writebytes(state, 0x21, &buf, 1); + + while (count < 20) { + nxt200x_readbytes(state, 0x21, &buf, 1); + if ((buf & 0x80)== 0x00) + return 0; + msleep(100); + count++; + } + printk("nxt2002: timeout error writing tuner\n"); + break; + default: + return -EINVAL; + break; + } + return 0; +} + +static void nxt200x_agc_reset(struct nxt200x_state* state) +{ + u8 buf; + dprintk("%s\n", __FUNCTION__); + + switch (state->demod_chip) { + case NXT2002: + buf = 0x08; + nxt200x_writebytes(state, 0x08, &buf, 1); + buf = 0x00; + nxt200x_writebytes(state, 0x08, &buf, 1); + break; + case NXT2004: + nxt200x_readreg_multibyte(state, 0x08, &buf, 1); + buf = 0x08; + nxt200x_writereg_multibyte(state, 0x08, &buf, 1); + buf = 0x00; + nxt200x_writereg_multibyte(state, 0x08, &buf, 1); + break; + default: + break; + } + return; +} + +static int nxt2002_load_firmware (struct dvb_frontend* fe, const struct firmware *fw) +{ + + struct nxt200x_state* state = fe->demodulator_priv; + u8 buf[3], written = 0, chunkpos = 0; + u16 rambase, position, crc = 0; + + dprintk("%s\n", __FUNCTION__); + dprintk("Firmware is %zu bytes\n", fw->size); + + /* Get the RAM base for this nxt2002 */ + nxt200x_readbytes(state, 0x10, buf, 1); + + if (buf[0] & 0x10) + rambase = 0x1000; + else + rambase = 0x0000; + + dprintk("rambase on this nxt2002 is %04X\n", rambase); + + /* Hold the micro in reset while loading firmware */ + buf[0] = 0x80; + nxt200x_writebytes(state, 0x2B, buf, 1); + + for (position = 0; position < fw->size; position++) { + if (written == 0) { + crc = 0; + chunkpos = 0x28; + buf[0] = ((rambase + position) >> 8); + buf[1] = (rambase + position) & 0xFF; + buf[2] = 0x81; + /* write starting address */ + nxt200x_writebytes(state, 0x29, buf, 3); + } + written++; + chunkpos++; + + if ((written % 4) == 0) + nxt200x_writebytes(state, chunkpos, &fw->data[position-3], 4); + + crc = nxt200x_crc(crc, fw->data[position]); + + if ((written == 255) || (position+1 == fw->size)) { + /* write remaining bytes of firmware */ + nxt200x_writebytes(state, chunkpos+4-(written %4), + &fw->data[position-(written %4) + 1], + written %4); + buf[0] = crc << 8; + buf[1] = crc & 0xFF; + + /* write crc */ + nxt200x_writebytes(state, 0x2C, buf, 2); + + /* do a read to stop things */ + nxt200x_readbytes(state, 0x2A, buf, 1); + + /* set transfer mode to complete */ + buf[0] = 0x80; + nxt200x_writebytes(state, 0x2B, buf, 1); + + written = 0; + } + } + + return 0; +}; + +static int nxt2004_load_firmware (struct dvb_frontend* fe, const struct firmware *fw) +{ + + struct nxt200x_state* state = fe->demodulator_priv; + u8 buf[3]; + u16 rambase, position, crc=0; + + dprintk("%s\n", __FUNCTION__); + dprintk("Firmware is %zu bytes\n", fw->size); + + /* set rambase */ + rambase = 0x1000; + + /* hold the micro in reset while loading firmware */ + buf[0] = 0x80; + nxt200x_writebytes(state, 0x2B, buf,1); + + /* calculate firmware CRC */ + for (position = 0; position < fw->size; position++) { + crc = nxt200x_crc(crc, fw->data[position]); + } + + buf[0] = rambase >> 8; + buf[1] = rambase & 0xFF; + buf[2] = 0x81; + /* write starting address */ + nxt200x_writebytes(state,0x29,buf,3); + + for (position = 0; position < fw->size;) { + nxt200x_writebytes(state, 0x2C, &fw->data[position], + fw->size-position > 255 ? 255 : fw->size-position); + position += (fw->size-position > 255 ? 255 : fw->size-position); + } + buf[0] = crc >> 8; + buf[1] = crc & 0xFF; + + dprintk("firmware crc is 0x%02X 0x%02X\n", buf[0], buf[1]); + + /* write crc */ + nxt200x_writebytes(state, 0x2C, buf,2); + + /* do a read to stop things */ + nxt200x_readbytes(state, 0x2C, buf, 1); + + /* set transfer mode to complete */ + buf[0] = 0x80; + nxt200x_writebytes(state, 0x2B, buf,1); + + return 0; +}; + +static int nxt200x_setup_frontend_parameters (struct dvb_frontend* fe, + struct dvb_frontend_parameters *p) +{ + struct nxt200x_state* state = fe->demodulator_priv; + u8 buf[4]; + + /* stop the micro first */ + nxt200x_microcontroller_stop(state); + + if (state->demod_chip == NXT2004) { + /* make sure demod is set to digital */ + buf[0] = 0x04; + nxt200x_writebytes(state, 0x14, buf, 1); + buf[0] = 0x00; + nxt200x_writebytes(state, 0x17, buf, 1); + } + + /* get tuning information */ + dvb_pll_configure(state->config->pll_desc, buf, p->frequency, 0); + + /* set additional params */ + switch (p->u.vsb.modulation) { + case QAM_64: + case QAM_256: + /* Set punctured clock for QAM */ + /* This is just a guess since I am unable to test it */ + if (state->config->set_ts_params) + state->config->set_ts_params(fe, 1); + + /* set input */ + if (state->config->set_pll_input) + state->config->set_pll_input(buf, 1); + break; + case VSB_8: + /* Set non-punctured clock for VSB */ + if (state->config->set_ts_params) + state->config->set_ts_params(fe, 0); + + /* set input */ + if (state->config->set_pll_input) + state->config->set_pll_input(buf, 0); + break; + default: + return -EINVAL; + break; + } + + /* write frequency information */ + nxt200x_writetuner(state, buf); + + /* reset the agc now that tuning has been completed */ + nxt200x_agc_reset(state); + + /* set target power level */ + switch (p->u.vsb.modulation) { + case QAM_64: + case QAM_256: + buf[0] = 0x74; + break; + case VSB_8: + buf[0] = 0x70; + break; + default: + return -EINVAL; + break; + } + nxt200x_writebytes(state, 0x42, buf, 1); + + /* configure sdm */ + switch (state->demod_chip) { + case NXT2002: + buf[0] = 0x87; + break; + case NXT2004: + buf[0] = 0x07; + break; + default: + return -EINVAL; + break; + } + nxt200x_writebytes(state, 0x57, buf, 1); + + /* write sdm1 input */ + buf[0] = 0x10; + buf[1] = 0x00; + nxt200x_writebytes(state, 0x58, buf, 2); + + /* write sdmx input */ + switch (p->u.vsb.modulation) { + case QAM_64: + buf[0] = 0x68; + break; + case QAM_256: + buf[0] = 0x64; + break; + case VSB_8: + buf[0] = 0x60; + break; + default: + return -EINVAL; + break; + } + buf[1] = 0x00; + nxt200x_writebytes(state, 0x5C, buf, 2); + + /* write adc power lpf fc */ + buf[0] = 0x05; + nxt200x_writebytes(state, 0x43, buf, 1); + + if (state->demod_chip == NXT2004) { + /* write ??? */ + buf[0] = 0x00; + buf[1] = 0x00; + nxt200x_writebytes(state, 0x46, buf, 2); + } + + /* write accumulator2 input */ + buf[0] = 0x80; + buf[1] = 0x00; + nxt200x_writebytes(state, 0x4B, buf, 2); + + /* write kg1 */ + buf[0] = 0x00; + nxt200x_writebytes(state, 0x4D, buf, 1); + + /* write sdm12 lpf fc */ + buf[0] = 0x44; + nxt200x_writebytes(state, 0x55, buf, 1); + + /* write agc control reg */ + buf[0] = 0x04; + nxt200x_writebytes(state, 0x41, buf, 1); + + if (state->demod_chip == NXT2004) { + nxt200x_readreg_multibyte(state, 0x80, buf, 1); + buf[0] = 0x24; + nxt200x_writereg_multibyte(state, 0x80, buf, 1); + + /* soft reset? */ + nxt200x_readreg_multibyte(state, 0x08, buf, 1); + buf[0] = 0x10; + nxt200x_writereg_multibyte(state, 0x08, buf, 1); + nxt200x_readreg_multibyte(state, 0x08, buf, 1); + buf[0] = 0x00; + nxt200x_writereg_multibyte(state, 0x08, buf, 1); + + nxt200x_readreg_multibyte(state, 0x80, buf, 1); + buf[0] = 0x04; + nxt200x_writereg_multibyte(state, 0x80, buf, 1); + buf[0] = 0x00; + nxt200x_writereg_multibyte(state, 0x81, buf, 1); + buf[0] = 0x80; buf[1] = 0x00; buf[2] = 0x00; + nxt200x_writereg_multibyte(state, 0x82, buf, 3); + nxt200x_readreg_multibyte(state, 0x88, buf, 1); + buf[0] = 0x11; + nxt200x_writereg_multibyte(state, 0x88, buf, 1); + nxt200x_readreg_multibyte(state, 0x80, buf, 1); + buf[0] = 0x44; + nxt200x_writereg_multibyte(state, 0x80, buf, 1); + } + + /* write agc ucgp0 */ + switch (p->u.vsb.modulation) { + case QAM_64: + buf[0] = 0x02; + break; + case QAM_256: + buf[0] = 0x03; + break; + case VSB_8: + buf[0] = 0x00; + break; + default: + return -EINVAL; + break; + } + nxt200x_writebytes(state, 0x30, buf, 1); + + /* write agc control reg */ + buf[0] = 0x00; + nxt200x_writebytes(state, 0x41, buf, 1); + + /* write accumulator2 input */ + buf[0] = 0x80; + buf[1] = 0x00; + nxt200x_writebytes(state, 0x49, buf,2); + nxt200x_writebytes(state, 0x4B, buf,2); + + /* write agc control reg */ + buf[0] = 0x04; + nxt200x_writebytes(state, 0x41, buf, 1); + + nxt200x_microcontroller_start(state); + + if (state->demod_chip == NXT2004) { + nxt2004_microcontroller_init(state); + + /* ???? */ + buf[0] = 0xF0; + buf[1] = 0x00; + nxt200x_writebytes(state, 0x5C, buf, 2); + } + + /* adjacent channel detection should be done here, but I don't + have any stations with this need so I cannot test it */ + + return 0; +} + +static int nxt200x_read_status(struct dvb_frontend* fe, fe_status_t* status) +{ + struct nxt200x_state* state = fe->demodulator_priv; + u8 lock; + nxt200x_readbytes(state, 0x31, &lock, 1); + + *status = 0; + if (lock & 0x20) { + *status |= FE_HAS_SIGNAL; + *status |= FE_HAS_CARRIER; + *status |= FE_HAS_VITERBI; + *status |= FE_HAS_SYNC; + *status |= FE_HAS_LOCK; + } + return 0; +} + +static int nxt200x_read_ber(struct dvb_frontend* fe, u32* ber) +{ + struct nxt200x_state* state = fe->demodulator_priv; + u8 b[3]; + + nxt200x_readreg_multibyte(state, 0xE6, b, 3); + + *ber = ((b[0] << 8) + b[1]) * 8; + + return 0; +} + +static int nxt200x_read_signal_strength(struct dvb_frontend* fe, u16* strength) +{ + struct nxt200x_state* state = fe->demodulator_priv; + u8 b[2]; + u16 temp = 0; + + /* setup to read cluster variance */ + b[0] = 0x00; + nxt200x_writebytes(state, 0xA1, b, 1); + + /* get multreg val */ + nxt200x_readreg_multibyte(state, 0xA6, b, 2); + + temp = (b[0] << 8) | b[1]; + *strength = ((0x7FFF - temp) & 0x0FFF) * 16; + + return 0; +} + +static int nxt200x_read_snr(struct dvb_frontend* fe, u16* snr) +{ + + struct nxt200x_state* state = fe->demodulator_priv; + u8 b[2]; + u16 temp = 0, temp2; + u32 snrdb = 0; + + /* setup to read cluster variance */ + b[0] = 0x00; + nxt200x_writebytes(state, 0xA1, b, 1); + + /* get multreg val from 0xA6 */ + nxt200x_readreg_multibyte(state, 0xA6, b, 2); + + temp = (b[0] << 8) | b[1]; + temp2 = 0x7FFF - temp; + + /* snr will be in db */ + if (temp2 > 0x7F00) + snrdb = 1000*24 + ( 1000*(30-24) * ( temp2 - 0x7F00 ) / ( 0x7FFF - 0x7F00 ) ); + else if (temp2 > 0x7EC0) + snrdb = 1000*18 + ( 1000*(24-18) * ( temp2 - 0x7EC0 ) / ( 0x7F00 - 0x7EC0 ) ); + else if (temp2 > 0x7C00) + snrdb = 1000*12 + ( 1000*(18-12) * ( temp2 - 0x7C00 ) / ( 0x7EC0 - 0x7C00 ) ); + else + snrdb = 1000*0 + ( 1000*(12-0) * ( temp2 - 0 ) / ( 0x7C00 - 0 ) ); + + /* the value reported back from the frontend will be FFFF=32db 0000=0db */ + *snr = snrdb * (0xFFFF/32000); + + return 0; +} + +static int nxt200x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) +{ + struct nxt200x_state* state = fe->demodulator_priv; + u8 b[3]; + + nxt200x_readreg_multibyte(state, 0xE6, b, 3); + *ucblocks = b[2]; + + return 0; +} + +static int nxt200x_sleep(struct dvb_frontend* fe) +{ + return 0; +} + +static int nxt2002_init(struct dvb_frontend* fe) +{ + struct nxt200x_state* state = fe->demodulator_priv; + const struct firmware *fw; + int ret; + u8 buf[2]; + + /* request the firmware, this will block until someone uploads it */ + printk("nxt2002: Waiting for firmware upload (%s)...\n", NXT2002_DEFAULT_FIRMWARE); + ret = request_firmware(&fw, NXT2002_DEFAULT_FIRMWARE, &state->i2c->dev); + printk("nxt2002: Waiting for firmware upload(2)...\n"); + if (ret) { + printk("nxt2002: No firmware uploaded (timeout or file not found?)\n"); + return ret; + } + + ret = nxt2002_load_firmware(fe, fw); + if (ret) { + printk("nxt2002: Writing firmware to device failed\n"); + release_firmware(fw); + return ret; + } + printk("nxt2002: Firmware upload complete\n"); + + /* Put the micro into reset */ + nxt200x_microcontroller_stop(state); + + /* ensure transfer is complete */ + buf[0]=0x00; + nxt200x_writebytes(state, 0x2B, buf, 1); + + /* Put the micro into reset for real this time */ + nxt200x_microcontroller_stop(state); + + /* soft reset everything (agc,frontend,eq,fec)*/ + buf[0] = 0x0F; + nxt200x_writebytes(state, 0x08, buf, 1); + buf[0] = 0x00; + nxt200x_writebytes(state, 0x08, buf, 1); + + /* write agc sdm configure */ + buf[0] = 0xF1; + nxt200x_writebytes(state, 0x57, buf, 1); + + /* write mod output format */ + buf[0] = 0x20; + nxt200x_writebytes(state, 0x09, buf, 1); + + /* write fec mpeg mode */ + buf[0] = 0x7E; + buf[1] = 0x00; + nxt200x_writebytes(state, 0xE9, buf, 2); + + /* write mux selection */ + buf[0] = 0x00; + nxt200x_writebytes(state, 0xCC, buf, 1); + + return 0; +} + +static int nxt2004_init(struct dvb_frontend* fe) +{ + struct nxt200x_state* state = fe->demodulator_priv; + const struct firmware *fw; + int ret; + u8 buf[3]; + + /* ??? */ + buf[0]=0x00; + nxt200x_writebytes(state, 0x1E, buf, 1); + + /* request the firmware, this will block until someone uploads it */ + printk("nxt2004: Waiting for firmware upload (%s)...\n", NXT2004_DEFAULT_FIRMWARE); + ret = request_firmware(&fw, NXT2004_DEFAULT_FIRMWARE, &state->i2c->dev); + printk("nxt2004: Waiting for firmware upload(2)...\n"); + if (ret) { + printk("nxt2004: No firmware uploaded (timeout or file not found?)\n"); + return ret; + } + + ret = nxt2004_load_firmware(fe, fw); + if (ret) { + printk("nxt2004: Writing firmware to device failed\n"); + release_firmware(fw); + return ret; + } + printk("nxt2004: Firmware upload complete\n"); + + /* ensure transfer is complete */ + buf[0] = 0x01; + nxt200x_writebytes(state, 0x19, buf, 1); + + nxt2004_microcontroller_init(state); + nxt200x_microcontroller_stop(state); + nxt200x_microcontroller_stop(state); + nxt2004_microcontroller_init(state); + nxt200x_microcontroller_stop(state); + + /* soft reset everything (agc,frontend,eq,fec)*/ + buf[0] = 0xFF; + nxt200x_writereg_multibyte(state, 0x08, buf, 1); + buf[0] = 0x00; + nxt200x_writereg_multibyte(state, 0x08, buf, 1); + + /* write agc sdm configure */ + buf[0] = 0xD7; + nxt200x_writebytes(state, 0x57, buf, 1); + + /* ???*/ + buf[0] = 0x07; + buf[1] = 0xfe; + nxt200x_writebytes(state, 0x35, buf, 2); + buf[0] = 0x12; + nxt200x_writebytes(state, 0x34, buf, 1); + buf[0] = 0x80; + nxt200x_writebytes(state, 0x21, buf, 1); + + /* ???*/ + buf[0] = 0x21; + nxt200x_writebytes(state, 0x0A, buf, 1); + + /* ???*/ + buf[0] = 0x01; + nxt200x_writereg_multibyte(state, 0x80, buf, 1); + + /* write fec mpeg mode */ + buf[0] = 0x7E; + buf[1] = 0x00; + nxt200x_writebytes(state, 0xE9, buf, 2); + + /* write mux selection */ + buf[0] = 0x00; + nxt200x_writebytes(state, 0xCC, buf, 1); + + /* ???*/ + nxt200x_readreg_multibyte(state, 0x80, buf, 1); + buf[0] = 0x00; + nxt200x_writereg_multibyte(state, 0x80, buf, 1); + + /* soft reset? */ + nxt200x_readreg_multibyte(state, 0x08, buf, 1); + buf[0] = 0x10; + nxt200x_writereg_multibyte(state, 0x08, buf, 1); + nxt200x_readreg_multibyte(state, 0x08, buf, 1); + buf[0] = 0x00; + nxt200x_writereg_multibyte(state, 0x08, buf, 1); + + /* ???*/ + nxt200x_readreg_multibyte(state, 0x80, buf, 1); + buf[0] = 0x01; + nxt200x_writereg_multibyte(state, 0x80, buf, 1); + buf[0] = 0x70; + nxt200x_writereg_multibyte(state, 0x81, buf, 1); + buf[0] = 0x31; buf[1] = 0x5E; buf[2] = 0x66; + nxt200x_writereg_multibyte(state, 0x82, buf, 3); + + nxt200x_readreg_multibyte(state, 0x88, buf, 1); + buf[0] = 0x11; + nxt200x_writereg_multibyte(state, 0x88, buf, 1); + nxt200x_readreg_multibyte(state, 0x80, buf, 1); + buf[0] = 0x40; + nxt200x_writereg_multibyte(state, 0x80, buf, 1); + + nxt200x_readbytes(state, 0x10, buf, 1); + buf[0] = 0x10; + nxt200x_writebytes(state, 0x10, buf, 1); + nxt200x_readbytes(state, 0x0A, buf, 1); + buf[0] = 0x21; + nxt200x_writebytes(state, 0x0A, buf, 1); + + nxt2004_microcontroller_init(state); + + buf[0] = 0x21; + nxt200x_writebytes(state, 0x0A, buf, 1); + buf[0] = 0x7E; + nxt200x_writebytes(state, 0xE9, buf, 1); + buf[0] = 0x00; + nxt200x_writebytes(state, 0xEA, buf, 1); + + nxt200x_readreg_multibyte(state, 0x80, buf, 1); + buf[0] = 0x00; + nxt200x_writereg_multibyte(state, 0x80, buf, 1); + nxt200x_readreg_multibyte(state, 0x80, buf, 1); + buf[0] = 0x00; + nxt200x_writereg_multibyte(state, 0x80, buf, 1); + + /* soft reset? */ + nxt200x_readreg_multibyte(state, 0x08, buf, 1); + buf[0] = 0x10; + nxt200x_writereg_multibyte(state, 0x08, buf, 1); + nxt200x_readreg_multibyte(state, 0x08, buf, 1); + buf[0] = 0x00; + nxt200x_writereg_multibyte(state, 0x08, buf, 1); + + nxt200x_readreg_multibyte(state, 0x80, buf, 1); + buf[0] = 0x04; + nxt200x_writereg_multibyte(state, 0x80, buf, 1); + buf[0] = 0x00; + nxt200x_writereg_multibyte(state, 0x81, buf, 1); + buf[0] = 0x80; buf[1] = 0x00; buf[2] = 0x00; + nxt200x_writereg_multibyte(state, 0x82, buf, 3); + + nxt200x_readreg_multibyte(state, 0x88, buf, 1); + buf[0] = 0x11; + nxt200x_writereg_multibyte(state, 0x88, buf, 1); + + nxt200x_readreg_multibyte(state, 0x80, buf, 1); + buf[0] = 0x44; + nxt200x_writereg_multibyte(state, 0x80, buf, 1); + + /* initialize tuner */ + nxt200x_readbytes(state, 0x10, buf, 1); + buf[0] = 0x12; + nxt200x_writebytes(state, 0x10, buf, 1); + buf[0] = 0x04; + nxt200x_writebytes(state, 0x13, buf, 1); + buf[0] = 0x00; + nxt200x_writebytes(state, 0x16, buf, 1); + buf[0] = 0x04; + nxt200x_writebytes(state, 0x14, buf, 1); + buf[0] = 0x00; + nxt200x_writebytes(state, 0x14, buf, 1); + nxt200x_writebytes(state, 0x17, buf, 1); + nxt200x_writebytes(state, 0x14, buf, 1); + nxt200x_writebytes(state, 0x17, buf, 1); + + return 0; +} + +static int nxt200x_init(struct dvb_frontend* fe) +{ + struct nxt200x_state* state = fe->demodulator_priv; + int ret = 0; + + if (!state->initialised) { + switch (state->demod_chip) { + case NXT2002: + ret = nxt2002_init(fe); + break; + case NXT2004: + ret = nxt2004_init(fe); + break; + default: + return -EINVAL; + break; + } + state->initialised = 1; + } + return ret; +} + +static int nxt200x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) +{ + fesettings->min_delay_ms = 500; + fesettings->step_size = 0; + fesettings->max_drift = 0; + return 0; +} + +static void nxt200x_release(struct dvb_frontend* fe) +{ + struct nxt200x_state* state = fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops nxt200x_ops; + +struct dvb_frontend* nxt200x_attach(const struct nxt200x_config* config, + struct i2c_adapter* i2c) +{ + struct nxt200x_state* state = NULL; + u8 buf [] = {0,0,0,0,0}; + + /* allocate memory for the internal state */ + state = (struct nxt200x_state*) kmalloc(sizeof(struct nxt200x_state), GFP_KERNEL); + if (state == NULL) + goto error; + memset(state,0,sizeof(*state)); + + /* setup the state */ + state->config = config; + state->i2c = i2c; + memcpy(&state->ops, &nxt200x_ops, sizeof(struct dvb_frontend_ops)); + state->initialised = 0; + + /* read card id */ + nxt200x_readbytes(state, 0x00, buf, 5); + dprintk("NXT info: %02X %02X %02X %02X %02X\n", + buf[0], buf[1], buf[2], buf[3], buf[4]); + + /* set demod chip */ + switch (buf[0]) { + case 0x04: + state->demod_chip = NXT2002; + printk("nxt200x: NXT2002 Detected\n"); + break; + case 0x05: + state->demod_chip = NXT2004; + printk("nxt200x: NXT2004 Detected\n"); + break; + default: + goto error; + } + + /* make sure demod chip is supported */ + switch (state->demod_chip) { + case NXT2002: + if (buf[0] != 0x04) goto error; /* device id */ + if (buf[1] != 0x02) goto error; /* fab id */ + if (buf[2] != 0x11) goto error; /* month */ + if (buf[3] != 0x20) goto error; /* year msb */ + if (buf[4] != 0x00) goto error; /* year lsb */ + break; + case NXT2004: + if (buf[0] != 0x05) goto error; /* device id */ + break; + default: + goto error; + } + + /* create dvb_frontend */ + state->frontend.ops = &state->ops; + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + kfree(state); + printk("Unknown/Unsupported NXT chip: %02X %02X %02X %02X %02X\n", + buf[0], buf[1], buf[2], buf[3], buf[4]); + return NULL; +} + +static struct dvb_frontend_ops nxt200x_ops = { + + .info = { + .name = "Nextwave NXT200X VSB/QAM frontend", + .type = FE_ATSC, + .frequency_min = 54000000, + .frequency_max = 860000000, + .frequency_stepsize = 166666, /* stepsize is just a guess */ + .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_8VSB | FE_CAN_QAM_64 | FE_CAN_QAM_256 + }, + + .release = nxt200x_release, + + .init = nxt200x_init, + .sleep = nxt200x_sleep, + + .set_frontend = nxt200x_setup_frontend_parameters, + .get_tune_settings = nxt200x_get_tune_settings, + + .read_status = nxt200x_read_status, + .read_ber = nxt200x_read_ber, + .read_signal_strength = nxt200x_read_signal_strength, + .read_snr = nxt200x_read_snr, + .read_ucblocks = nxt200x_read_ucblocks, +}; + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + +MODULE_DESCRIPTION("NXT200X (ATSC 8VSB & ITU-T J.83 AnnexB 64/256 QAM) Demodulator Driver"); +MODULE_AUTHOR("Kirk Lapray, Jean-Francois Thibert, and Taylor Jacob"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(nxt200x_attach); + diff --git a/drivers/media/dvb/frontends/nxt200x.h b/drivers/media/dvb/frontends/nxt200x.h new file mode 100644 index 000000000000..1d9d70bc37ef --- /dev/null +++ b/drivers/media/dvb/frontends/nxt200x.h @@ -0,0 +1,61 @@ +/* + * Support for NXT2002 and NXT2004 - VSB/QAM + * + * Copyright (C) 2005 Kirk Lapray (kirk.lapray@gmail.com) + * based on nxt2002 by Taylor Jacob <rtjacob@earthlink.net> + * and nxt2004 by Jean-Francois Thibert (jeanfrancois@sagetv.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 NXT200X_H +#define NXT200X_H + +#include <linux/dvb/frontend.h> +#include <linux/firmware.h> + +typedef enum nxt_chip_t { + NXTUNDEFINED, + NXT2002, + NXT2004 +}nxt_chip_type; + +struct nxt200x_config +{ + /* the demodulator's i2c address */ + u8 demod_address; + + /* tuner information */ + u8 pll_address; + struct dvb_pll_desc *pll_desc; + + /* used to set pll input */ + int (*set_pll_input)(u8* buf, int input); + + /* need to set device param for start_dma */ + int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured); +}; + +extern struct dvb_frontend* nxt200x_attach(const struct nxt200x_config* config, + struct i2c_adapter* i2c); + +#endif /* NXT200X_H */ + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/dvb/frontends/or51132.c b/drivers/media/dvb/frontends/or51132.c index b6d0eecc59eb..78bded861d02 100644 --- a/drivers/media/dvb/frontends/or51132.c +++ b/drivers/media/dvb/frontends/or51132.c @@ -36,6 +36,8 @@ #include <linux/moduleparam.h> #include <linux/init.h> #include <linux/delay.h> +#include <linux/string.h> +#include <linux/slab.h> #include <asm/byteorder.h> #include "dvb_frontend.h" @@ -466,6 +468,7 @@ static int or51132_read_signal_strength(struct dvb_frontend* fe, u16* strength) unsigned char snd_buf[2]; u8 rcvr_stat; u16 snr_equ; + u32 signal_strength; int usK; snd_buf[0]=0x04; @@ -501,7 +504,11 @@ static int or51132_read_signal_strength(struct dvb_frontend* fe, u16* strength) usK = (rcvr_stat & 0x10) ? 3 : 0; /* The value reported back from the frontend will be FFFF=100% 0000=0% */ - *strength = (((8952 - i20Log10(snr_equ) - usK*100)/3+5)*65535)/1000; + signal_strength = (((8952 - i20Log10(snr_equ) - usK*100)/3+5)*65535)/1000; + if (signal_strength > 0xffff) + *strength = 0xffff; + else + *strength = signal_strength; dprintk("read_signal_strength %i\n",*strength); return 0; @@ -575,8 +582,7 @@ struct dvb_frontend* or51132_attach(const struct or51132_config* config, return &state->frontend; error: - if (state) - kfree(state); + kfree(state); return NULL; } diff --git a/drivers/media/dvb/frontends/or51211.c b/drivers/media/dvb/frontends/or51211.c index ad56a9958404..531f76246e5f 100644 --- a/drivers/media/dvb/frontends/or51211.c +++ b/drivers/media/dvb/frontends/or51211.c @@ -34,6 +34,8 @@ #include <linux/moduleparam.h> #include <linux/device.h> #include <linux/firmware.h> +#include <linux/string.h> +#include <linux/slab.h> #include <asm/byteorder.h> #include "dvb_frontend.h" @@ -337,6 +339,7 @@ static int or51211_read_signal_strength(struct dvb_frontend* fe, u16* strength) u8 rec_buf[2]; u8 snd_buf[4]; u8 snr_equ; + u32 signal_strength; /* SNR after Equalizer */ snd_buf[0] = 0x04; @@ -356,8 +359,11 @@ static int or51211_read_signal_strength(struct dvb_frontend* fe, u16* strength) snr_equ = rec_buf[0] & 0xff; /* The value reported back from the frontend will be FFFF=100% 0000=0% */ - *strength = (((5334 - i20Log10(snr_equ))/3+5)*65535)/1000; - + signal_strength = (((5334 - i20Log10(snr_equ))/3+5)*65535)/1000; + if (signal_strength > 0xffff) + *strength = 0xffff; + else + *strength = signal_strength; dprintk("read_signal_strength %i\n",*strength); return 0; diff --git a/drivers/media/dvb/frontends/s5h1420.c b/drivers/media/dvb/frontends/s5h1420.c index c7fe27fd530c..f265418e3261 100644 --- a/drivers/media/dvb/frontends/s5h1420.c +++ b/drivers/media/dvb/frontends/s5h1420.c @@ -26,6 +26,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #include <linux/string.h> #include <linux/slab.h> #include <linux/delay.h> +#include <linux/jiffies.h> +#include <asm/div64.h> #include "dvb_frontend.h" #include "s5h1420.h" diff --git a/drivers/media/dvb/frontends/sp8870.c b/drivers/media/dvb/frontends/sp8870.c index 764a95a2e212..1c6b2e9264bc 100644 --- a/drivers/media/dvb/frontends/sp8870.c +++ b/drivers/media/dvb/frontends/sp8870.c @@ -32,6 +32,8 @@ #include <linux/device.h> #include <linux/firmware.h> #include <linux/delay.h> +#include <linux/string.h> +#include <linux/slab.h> #include "dvb_frontend.h" #include "sp8870.h" diff --git a/drivers/media/dvb/frontends/sp887x.c b/drivers/media/dvb/frontends/sp887x.c index d868a6927a16..73384e75625e 100644 --- a/drivers/media/dvb/frontends/sp887x.c +++ b/drivers/media/dvb/frontends/sp887x.c @@ -14,6 +14,8 @@ #include <linux/moduleparam.h> #include <linux/device.h> #include <linux/firmware.h> +#include <linux/string.h> +#include <linux/slab.h> #include "dvb_frontend.h" #include "sp887x.h" diff --git a/drivers/media/dvb/frontends/stv0297.c b/drivers/media/dvb/frontends/stv0297.c index 8d09afd7545d..6122ba754bc5 100644 --- a/drivers/media/dvb/frontends/stv0297.c +++ b/drivers/media/dvb/frontends/stv0297.c @@ -24,6 +24,8 @@ #include <linux/module.h> #include <linux/string.h> #include <linux/delay.h> +#include <linux/jiffies.h> +#include <linux/slab.h> #include "dvb_frontend.h" #include "stv0297.h" diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c index 2d62931f20b5..29c48665e130 100644 --- a/drivers/media/dvb/frontends/stv0299.c +++ b/drivers/media/dvb/frontends/stv0299.c @@ -48,6 +48,7 @@ #include <linux/moduleparam.h> #include <linux/string.h> #include <linux/slab.h> +#include <linux/jiffies.h> #include <asm/div64.h> #include "dvb_frontend.h" @@ -63,8 +64,12 @@ struct stv0299_state { u32 tuner_frequency; u32 symbol_rate; fe_code_rate_t fec_inner; + int errmode; }; +#define STATUS_BER 0 +#define STATUS_UCBLOCKS 1 + static int debug; static int debug_legacy_dish_switch; #define dprintk(args...) \ @@ -382,36 +387,6 @@ static int stv0299_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltag }; } -static inline s32 stv0299_calc_usec_delay (struct timeval lasttime, struct timeval curtime) -{ - return ((curtime.tv_usec < lasttime.tv_usec) ? - 1000000 - lasttime.tv_usec + curtime.tv_usec : - curtime.tv_usec - lasttime.tv_usec); -} - -static void stv0299_sleep_until (struct timeval *waketime, u32 add_usec) -{ - struct timeval lasttime; - s32 delta, newdelta; - - waketime->tv_usec += add_usec; - if (waketime->tv_usec >= 1000000) { - waketime->tv_usec -= 1000000; - waketime->tv_sec++; - } - - do_gettimeofday (&lasttime); - delta = stv0299_calc_usec_delay (lasttime, *waketime); - if (delta > 2500) { - msleep ((delta - 1500) / 1000); - do_gettimeofday (&lasttime); - newdelta = stv0299_calc_usec_delay (lasttime, *waketime); - delta = (newdelta > delta) ? 0 : newdelta; - } - if (delta > 0) - udelay (delta); -} - static int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, u32 cmd) { struct stv0299_state* state = fe->demodulator_priv; @@ -439,7 +414,7 @@ static int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, u32 cmd) memcpy (&tv[0], &nexttime, sizeof (struct timeval)); stv0299_writeregI (state, 0x0c, reg0x0c | 0x50); /* set LNB to 18V */ - stv0299_sleep_until (&nexttime, 32000); + dvb_frontend_sleep_until(&nexttime, 32000); for (i=0; i<9; i++) { if (debug_legacy_dish_switch) @@ -453,13 +428,13 @@ static int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, u32 cmd) cmd = cmd >> 1; if (i != 8) - stv0299_sleep_until (&nexttime, 8000); + dvb_frontend_sleep_until(&nexttime, 8000); } if (debug_legacy_dish_switch) { printk ("%s(%d): switch delay (should be 32k followed by all 8k\n", __FUNCTION__, fe->dvb->num); - for (i=1; i < 10; i++) - printk ("%d: %d\n", i, stv0299_calc_usec_delay (tv[i-1] , tv[i])); + for (i = 1; i < 10; i++) + printk ("%d: %d\n", i, timeval_usec_diff(tv[i-1] , tv[i])); } return 0; @@ -516,8 +491,7 @@ static int stv0299_read_ber(struct dvb_frontend* fe, u32* ber) { struct stv0299_state* state = fe->demodulator_priv; - stv0299_writeregI(state, 0x34, (stv0299_readreg(state, 0x34) & 0xcf) | 0x10); - msleep(100); + if (state->errmode != STATUS_BER) return 0; *ber = (stv0299_readreg (state, 0x1d) << 8) | stv0299_readreg (state, 0x1e); return 0; @@ -556,9 +530,8 @@ static int stv0299_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) { struct stv0299_state* state = fe->demodulator_priv; - stv0299_writeregI(state, 0x34, (stv0299_readreg(state, 0x34) & 0xcf) | 0x30); - msleep(100); - *ucblocks = (stv0299_readreg (state, 0x1d) << 8) | stv0299_readreg (state, 0x1e); + if (state->errmode != STATUS_UCBLOCKS) *ucblocks = 0; + else *ucblocks = (stv0299_readreg (state, 0x1d) << 8) | stv0299_readreg (state, 0x1e); return 0; } @@ -580,49 +553,14 @@ static int stv0299_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par if (state->config->invert) invval = (~invval) & 1; stv0299_writeregI(state, 0x0c, (stv0299_readreg(state, 0x0c) & 0xfe) | invval); - if (state->config->enhanced_tuning) { - /* check if we should do a finetune */ - int frequency_delta = p->frequency - state->tuner_frequency; - int minmax = p->u.qpsk.symbol_rate / 2000; - if (minmax < 5000) minmax = 5000; - - if ((frequency_delta > -minmax) && (frequency_delta < minmax) && (frequency_delta != 0) && - (state->fec_inner == p->u.qpsk.fec_inner) && - (state->symbol_rate == p->u.qpsk.symbol_rate)) { - int Drot_freq = (frequency_delta << 16) / (state->config->mclk / 1000); - - // zap the derotator registers first - stv0299_writeregI(state, 0x22, 0x00); - stv0299_writeregI(state, 0x23, 0x00); - - // now set them as we want - stv0299_writeregI(state, 0x22, Drot_freq >> 8); - stv0299_writeregI(state, 0x23, Drot_freq); - } else { - /* A "normal" tune is requested */ - stv0299_writeregI(state, 0x05, 0xb5); /* enable i2c repeater on stv0299 */ - state->config->pll_set(fe, state->i2c, p); - stv0299_writeregI(state, 0x05, 0x35); /* disable i2c repeater on stv0299 */ - - stv0299_writeregI(state, 0x32, 0x80); - stv0299_writeregI(state, 0x22, 0x00); - stv0299_writeregI(state, 0x23, 0x00); - stv0299_writeregI(state, 0x32, 0x19); - stv0299_set_symbolrate (fe, p->u.qpsk.symbol_rate); - stv0299_set_FEC (state, p->u.qpsk.fec_inner); - } - } else { - stv0299_writeregI(state, 0x05, 0xb5); /* enable i2c repeater on stv0299 */ - state->config->pll_set(fe, state->i2c, p); - stv0299_writeregI(state, 0x05, 0x35); /* disable i2c repeater on stv0299 */ + stv0299_writeregI(state, 0x05, 0xb5); /* enable i2c repeater on stv0299 */ + state->config->pll_set(fe, state->i2c, p); + stv0299_writeregI(state, 0x05, 0x35); /* disable i2c repeater on stv0299 */ - stv0299_set_FEC (state, p->u.qpsk.fec_inner); - stv0299_set_symbolrate (fe, p->u.qpsk.symbol_rate); - stv0299_writeregI(state, 0x22, 0x00); - stv0299_writeregI(state, 0x23, 0x00); - stv0299_readreg (state, 0x23); - stv0299_writeregI(state, 0x12, 0xb9); - } + stv0299_set_FEC (state, p->u.qpsk.fec_inner); + stv0299_set_symbolrate (fe, p->u.qpsk.symbol_rate); + stv0299_writeregI(state, 0x22, 0x00); + stv0299_writeregI(state, 0x23, 0x00); state->tuner_frequency = p->frequency; state->fec_inner = p->u.qpsk.fec_inner; @@ -707,6 +645,7 @@ struct dvb_frontend* stv0299_attach(const struct stv0299_config* config, state->tuner_frequency = 0; state->symbol_rate = 0; state->fec_inner = 0; + state->errmode = STATUS_BER; /* check if the demod is there */ stv0299_writeregI(state, 0x02, 0x34); /* standby off */ diff --git a/drivers/media/dvb/frontends/stv0299.h b/drivers/media/dvb/frontends/stv0299.h index d0c4484861e1..9af3d71c89db 100644 --- a/drivers/media/dvb/frontends/stv0299.h +++ b/drivers/media/dvb/frontends/stv0299.h @@ -73,9 +73,6 @@ struct stv0299_config /* does the inversion require inversion? */ u8 invert:1; - /* Should the enhanced tuning code be used? */ - u8 enhanced_tuning:1; - /* Skip reinitialisation? */ u8 skip_reinit:1; diff --git a/drivers/media/dvb/frontends/tda10021.c b/drivers/media/dvb/frontends/tda10021.c index 87d5f4d8790f..eaf130e666d8 100644 --- a/drivers/media/dvb/frontends/tda10021.c +++ b/drivers/media/dvb/frontends/tda10021.c @@ -100,8 +100,8 @@ static u8 tda10021_readreg (struct tda10021_state* state, u8 reg) ret = i2c_transfer (state->i2c, msg, 2); if (ret != 2) - printk("DVB: TDA10021(%d): %s: readreg error (ret == %i)\n", - state->frontend.dvb->num, __FUNCTION__, ret); + printk("DVB: TDA10021: %s: readreg error (ret == %i)\n", + __FUNCTION__, ret); return b1[0]; } diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c index 74cea9f8d721..7968743826fc 100644 --- a/drivers/media/dvb/frontends/tda1004x.c +++ b/drivers/media/dvb/frontends/tda1004x.c @@ -32,6 +32,10 @@ #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/device.h> +#include <linux/jiffies.h> +#include <linux/string.h> +#include <linux/slab.h> + #include "dvb_frontend.h" #include "tda1004x.h" @@ -416,7 +420,7 @@ static void tda10046_init_plls(struct dvb_frontend* fe) struct tda1004x_state* state = fe->demodulator_priv; tda1004x_write_byteI(state, TDA10046H_CONFPLL1, 0xf0); - tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 10); // PLL M = 10 + tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 0x0a); // PLL M = 10 if (state->config->xtal_freq == TDA10046_XTAL_4M ) { dprintk("%s: setting up PLLs for a 4 MHz Xtal\n", __FUNCTION__); tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 0); // PLL P = N = 0 @@ -593,7 +597,10 @@ static int tda10046_init(struct dvb_frontend* fe) // Init the tuner PLL if (state->config->pll_init) { tda1004x_enable_tuner_i2c(state); - state->config->pll_init(fe); + if (state->config->pll_init(fe)) { + printk(KERN_ERR "tda1004x: pll init failed\n"); + return -EIO; + } tda1004x_disable_tuner_i2c(state); } @@ -663,7 +670,10 @@ static int tda1004x_set_fe(struct dvb_frontend* fe, // set frequency tda1004x_enable_tuner_i2c(state); - state->config->pll_set(fe, fe_params); + if (state->config->pll_set(fe, fe_params)) { + printk(KERN_ERR "tda1004x: pll set failed\n"); + return -EIO; + } tda1004x_disable_tuner_i2c(state); // Hardcoded to use auto as much as possible on the TDA10045 as it @@ -828,6 +838,8 @@ static int tda1004x_set_fe(struct dvb_frontend* fe, case TDA1004X_DEMOD_TDA10046: tda1004x_write_mask(state, TDA1004X_AUTO, 0x40, 0x40); + msleep(1); + tda1004x_write_mask(state, TDA10046H_AGC_CONF, 4, 1); break; } @@ -1125,7 +1137,12 @@ static int tda1004x_sleep(struct dvb_frontend* fe) if (state->config->pll_sleep != NULL) { tda1004x_enable_tuner_i2c(state); state->config->pll_sleep(fe); - tda1004x_disable_tuner_i2c(state); + if (state->config->if_freq != TDA10046_FREQ_052) { + /* special hack for Philips EUROPA Based boards: + * keep the I2c bridge open for tuner access in analog mode + */ + tda1004x_disable_tuner_i2c(state); + } } tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 1); break; diff --git a/drivers/media/dvb/frontends/tda8083.c b/drivers/media/dvb/frontends/tda8083.c index 168e013d23bd..c05cf1861051 100644 --- a/drivers/media/dvb/frontends/tda8083.c +++ b/drivers/media/dvb/frontends/tda8083.c @@ -30,6 +30,7 @@ #include <linux/moduleparam.h> #include <linux/string.h> #include <linux/slab.h> +#include <linux/jiffies.h> #include "dvb_frontend.h" #include "tda8083.h" diff --git a/drivers/media/dvb/frontends/ves1820.c b/drivers/media/dvb/frontends/ves1820.c index c6d276618e86..ad8647a3c85e 100644 --- a/drivers/media/dvb/frontends/ves1820.c +++ b/drivers/media/dvb/frontends/ves1820.c @@ -140,25 +140,25 @@ static int ves1820_set_symbolrate(struct ves1820_state *state, u32 symbolrate) /* yeuch! */ fpxin = state->config->xin * 10; fptmp = fpxin; do_div(fptmp, 123); - if (symbolrate < fptmp); + if (symbolrate < fptmp) SFIL = 1; fptmp = fpxin; do_div(fptmp, 160); - if (symbolrate < fptmp); + if (symbolrate < fptmp) SFIL = 0; fptmp = fpxin; do_div(fptmp, 246); - if (symbolrate < fptmp); + if (symbolrate < fptmp) SFIL = 1; fptmp = fpxin; do_div(fptmp, 320); - if (symbolrate < fptmp); + if (symbolrate < fptmp) SFIL = 0; fptmp = fpxin; do_div(fptmp, 492); - if (symbolrate < fptmp); + if (symbolrate < fptmp) SFIL = 1; fptmp = fpxin; do_div(fptmp, 640); - if (symbolrate < fptmp); + if (symbolrate < fptmp) SFIL = 0; fptmp = fpxin; do_div(fptmp, 984); - if (symbolrate < fptmp); + if (symbolrate < fptmp) SFIL = 1; fin = state->config->xin >> 4; diff --git a/drivers/media/dvb/pluto2/pluto2.c b/drivers/media/dvb/pluto2/pluto2.c index 85b437bbddcd..bbebd1c4caca 100644 --- a/drivers/media/dvb/pluto2/pluto2.c +++ b/drivers/media/dvb/pluto2/pluto2.c @@ -286,15 +286,10 @@ static void pluto_dma_end(struct pluto *pluto, unsigned int nbpackets) * although one packet has been transfered. */ if ((nbpackets == 0) || (nbpackets > TS_DMA_PACKETS)) { - unsigned int i = 0, valid; + unsigned int i = 0; while (pluto->dma_buf[i] == 0x47) i += 188; - valid = i / 188; - if (nbpackets != valid) { - dev_err(&pluto->pdev->dev, "nbpackets=%u valid=%u\n", - nbpackets, valid); - nbpackets = valid; - } + nbpackets = i / 188; } dvb_dmx_swfilter_packets(&pluto->demux, pluto->dma_buf, nbpackets); diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig index d8bf65877897..fa5034a9ecf5 100644 --- a/drivers/media/dvb/ttpci/Kconfig +++ b/drivers/media/dvb/ttpci/Kconfig @@ -81,6 +81,7 @@ config DVB_BUDGET_CI tristate "Budget cards with onboard CI connector" depends on DVB_CORE && PCI select VIDEO_SAA7146 + select DVB_STV0297 select DVB_STV0299 select DVB_TDA1004X help diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c index 22b203f8ff27..87ea52757a21 100644 --- a/drivers/media/dvb/ttpci/av7110.c +++ b/drivers/media/dvb/ttpci/av7110.c @@ -1566,7 +1566,7 @@ static u8 alps_bsru6_inittab[] = { 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */ 0x10, 0x3f, // AGC2 0x3d 0x11, 0x84, - 0x12, 0xb5, // Lock detect: -64 Carrier freq detect:on + 0x12, 0xb9, 0x15, 0xc9, // lock detector threshold 0x16, 0x00, 0x17, 0x00, @@ -1644,7 +1644,6 @@ static struct stv0299_config alps_bsru6_config = { .inittab = alps_bsru6_inittab, .mclk = 88000000UL, .invert = 1, - .enhanced_tuning = 0, .skip_reinit = 0, .lock_output = STV0229_LOCKOUTPUT_1, .volt13_op0_op1 = STV0299_VOLT13_OP1, @@ -1669,7 +1668,7 @@ static u8 alps_bsbe1_inittab[] = { 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */ 0x10, 0x3f, // AGC2 0x3d 0x11, 0x84, - 0x12, 0xb5, // Lock detect: -64 Carrier freq detect:on + 0x12, 0xb9, 0x15, 0xc9, // lock detector threshold 0x16, 0x00, 0x17, 0x00, @@ -1721,7 +1720,6 @@ static struct stv0299_config alps_bsbe1_config = { .inittab = alps_bsbe1_inittab, .mclk = 88000000UL, .invert = 1, - .enhanced_tuning = 0, .skip_reinit = 0, .min_delay_ms = 100, .set_symbol_rate = alps_bsru6_set_symbol_rate, diff --git a/drivers/media/dvb/ttpci/av7110_ca.c b/drivers/media/dvb/ttpci/av7110_ca.c index c3801e328fe9..6079e8865d5b 100644 --- a/drivers/media/dvb/ttpci/av7110_ca.c +++ b/drivers/media/dvb/ttpci/av7110_ca.c @@ -40,6 +40,7 @@ #include "av7110.h" #include "av7110_hw.h" +#include "av7110_ca.h" void CI_handle(struct av7110 *av7110, u8 *data, u16 len) diff --git a/drivers/media/dvb/ttpci/av7110_ir.c b/drivers/media/dvb/ttpci/av7110_ir.c index 357a3728ec68..f5e59fc924af 100644 --- a/drivers/media/dvb/ttpci/av7110_ir.c +++ b/drivers/media/dvb/ttpci/av7110_ir.c @@ -15,7 +15,7 @@ static int av_cnt; static struct av7110 *av_list[4]; -static struct input_dev input_dev; +static struct input_dev *input_dev; static u16 key_map [256] = { KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, @@ -43,10 +43,10 @@ static u16 key_map [256] = { static void av7110_emit_keyup(unsigned long data) { - if (!data || !test_bit(data, input_dev.key)) + if (!data || !test_bit(data, input_dev->key)) return; - input_event(&input_dev, EV_KEY, data, !!0); + input_event(input_dev, EV_KEY, data, !!0); } @@ -112,13 +112,13 @@ static void av7110_emit_key(unsigned long parm) if (timer_pending(&keyup_timer)) { del_timer(&keyup_timer); if (keyup_timer.data != keycode || new_toggle != old_toggle) { - input_event(&input_dev, EV_KEY, keyup_timer.data, !!0); - input_event(&input_dev, EV_KEY, keycode, !0); + input_event(input_dev, EV_KEY, keyup_timer.data, !!0); + input_event(input_dev, EV_KEY, keycode, !0); } else - input_event(&input_dev, EV_KEY, keycode, 2); + input_event(input_dev, EV_KEY, keycode, 2); } else - input_event(&input_dev, EV_KEY, keycode, !0); + input_event(input_dev, EV_KEY, keycode, !0); keyup_timer.expires = jiffies + UP_TIMEOUT; keyup_timer.data = keycode; @@ -132,13 +132,13 @@ static void input_register_keys(void) { int i; - memset(input_dev.keybit, 0, sizeof(input_dev.keybit)); + memset(input_dev->keybit, 0, sizeof(input_dev->keybit)); - for (i = 0; i < sizeof(key_map) / sizeof(key_map[0]); i++) { + for (i = 0; i < ARRAY_SIZE(key_map); i++) { if (key_map[i] > KEY_MAX) key_map[i] = 0; else if (key_map[i] > KEY_RESERVED) - set_bit(key_map[i], input_dev.keybit); + set_bit(key_map[i], input_dev->keybit); } } @@ -216,12 +216,17 @@ int __init av7110_ir_init(struct av7110 *av7110) init_timer(&keyup_timer); keyup_timer.data = 0; - input_dev.name = "DVB on-card IR receiver"; - set_bit(EV_KEY, input_dev.evbit); - set_bit(EV_REP, input_dev.evbit); + input_dev = input_allocate_device(); + if (!input_dev) + return -ENOMEM; + + input_dev->name = "DVB on-card IR receiver"; + + set_bit(EV_KEY, input_dev->evbit); + set_bit(EV_REP, input_dev->evbit); input_register_keys(); - input_register_device(&input_dev); - input_dev.timer.function = input_repeat_key; + input_register_device(input_dev); + input_dev->timer.function = input_repeat_key; e = create_proc_entry("av7110_ir", S_IFREG | S_IRUGO | S_IWUSR, NULL); if (e) { @@ -256,7 +261,7 @@ void __exit av7110_ir_exit(struct av7110 *av7110) if (av_cnt == 1) { del_timer_sync(&keyup_timer); remove_proc_entry("av7110_ir", NULL); - input_unregister_device(&input_dev); + input_unregister_device(input_dev); } av_cnt--; diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c index 7692cd23f839..9f51bae7194c 100644 --- a/drivers/media/dvb/ttpci/budget-av.c +++ b/drivers/media/dvb/ttpci/budget-av.c @@ -499,7 +499,7 @@ static u8 typhoon_cinergy1200s_inittab[] = { 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */ 0x10, 0x3f, // AGC2 0x3d 0x11, 0x84, - 0x12, 0xb5, // Lock detect: -64 Carrier freq detect:on + 0x12, 0xb9, 0x15, 0xc9, // lock detector threshold 0x16, 0x00, 0x17, 0x00, @@ -531,7 +531,6 @@ static struct stv0299_config typhoon_config = { .inittab = typhoon_cinergy1200s_inittab, .mclk = 88000000UL, .invert = 0, - .enhanced_tuning = 0, .skip_reinit = 0, .lock_output = STV0229_LOCKOUTPUT_1, .volt13_op0_op1 = STV0299_VOLT13_OP0, @@ -546,7 +545,6 @@ static struct stv0299_config cinergy_1200s_config = { .inittab = typhoon_cinergy1200s_inittab, .mclk = 88000000UL, .invert = 0, - .enhanced_tuning = 0, .skip_reinit = 0, .lock_output = STV0229_LOCKOUTPUT_0, .volt13_op0_op1 = STV0299_VOLT13_OP0, @@ -1022,6 +1020,8 @@ MODULE_DEVICE_TABLE(pci, pci_tbl); static struct saa7146_extension budget_extension = { .name = "budget_av", + .flags = SAA7146_I2C_SHORT_DELAY, + .pci_tbl = pci_tbl, .module = THIS_MODULE, diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c index 2980db3ef22f..b9b3cd9c0369 100644 --- a/drivers/media/dvb/ttpci/budget-ci.c +++ b/drivers/media/dvb/ttpci/budget-ci.c @@ -64,7 +64,7 @@ struct budget_ci { struct budget budget; - struct input_dev input_dev; + struct input_dev *input_dev; struct tasklet_struct msp430_irq_tasklet; struct tasklet_struct ciintf_irq_tasklet; int slot_status; @@ -145,7 +145,7 @@ static void msp430_ir_debounce(unsigned long data) static void msp430_ir_interrupt(unsigned long data) { struct budget_ci *budget_ci = (struct budget_ci *) data; - struct input_dev *dev = &budget_ci->input_dev; + struct input_dev *dev = budget_ci->input_dev; unsigned int code = ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8; @@ -181,25 +181,27 @@ static void msp430_ir_interrupt(unsigned long data) static int msp430_ir_init(struct budget_ci *budget_ci) { struct saa7146_dev *saa = budget_ci->budget.dev; + struct input_dev *input_dev; int i; - memset(&budget_ci->input_dev, 0, sizeof(struct input_dev)); + budget_ci->input_dev = input_dev = input_allocate_device(); + if (!input_dev) + return -ENOMEM; sprintf(budget_ci->ir_dev_name, "Budget-CI dvb ir receiver %s", saa->name); - budget_ci->input_dev.name = budget_ci->ir_dev_name; - set_bit(EV_KEY, budget_ci->input_dev.evbit); + input_dev->name = budget_ci->ir_dev_name; - for (i = 0; i < sizeof(key_map) / sizeof(*key_map); i++) + set_bit(EV_KEY, input_dev->evbit); + for (i = 0; i < ARRAY_SIZE(key_map); i++) if (key_map[i]) - set_bit(key_map[i], budget_ci->input_dev.keybit); + set_bit(key_map[i], input_dev->keybit); - input_register_device(&budget_ci->input_dev); + input_register_device(budget_ci->input_dev); - budget_ci->input_dev.timer.function = msp430_ir_debounce; + input_dev->timer.function = msp430_ir_debounce; saa7146_write(saa, IER, saa7146_read(saa, IER) | MASK_06); - saa7146_setgpio(saa, 3, SAA7146_GPIO_IRQHI); return 0; @@ -208,7 +210,7 @@ static int msp430_ir_init(struct budget_ci *budget_ci) static void msp430_ir_deinit(struct budget_ci *budget_ci) { struct saa7146_dev *saa = budget_ci->budget.dev; - struct input_dev *dev = &budget_ci->input_dev; + struct input_dev *dev = budget_ci->input_dev; saa7146_write(saa, IER, saa7146_read(saa, IER) & ~MASK_06); saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT); @@ -488,7 +490,7 @@ static u8 alps_bsru6_inittab[] = { 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */ 0x10, 0x3f, // AGC2 0x3d 0x11, 0x84, - 0x12, 0xb5, // Lock detect: -64 Carrier freq detect:on + 0x12, 0xb9, 0x15, 0xc9, // lock detector threshold 0x16, 0x00, 0x17, 0x00, @@ -578,7 +580,6 @@ static struct stv0299_config alps_bsru6_config = { .inittab = alps_bsru6_inittab, .mclk = 88000000UL, .invert = 1, - .enhanced_tuning = 0, .skip_reinit = 0, .lock_output = STV0229_LOCKOUTPUT_1, .volt13_op0_op1 = STV0299_VOLT13_OP1, @@ -708,7 +709,6 @@ static struct stv0299_config philips_su1278_tt_config = { .inittab = philips_su1278_tt_inittab, .mclk = 64000000UL, .invert = 0, - .enhanced_tuning = 1, .skip_reinit = 1, .lock_output = STV0229_LOCKOUTPUT_1, .volt13_op0_op1 = STV0299_VOLT13_OP1, @@ -1166,7 +1166,7 @@ MODULE_DEVICE_TABLE(pci, pci_tbl); static struct saa7146_extension budget_extension = { .name = "budget_ci dvb\0", - .flags = 0, + .flags = SAA7146_I2C_SHORT_DELAY, .module = THIS_MODULE, .pci_tbl = &pci_tbl[0], diff --git a/drivers/media/dvb/ttpci/budget-patch.c b/drivers/media/dvb/ttpci/budget-patch.c index b1f21ef0e3b3..755df81cbc49 100644 --- a/drivers/media/dvb/ttpci/budget-patch.c +++ b/drivers/media/dvb/ttpci/budget-patch.c @@ -305,7 +305,7 @@ static u8 alps_bsru6_inittab[] = { 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */ 0x10, 0x3f, // AGC2 0x3d 0x11, 0x84, - 0x12, 0xb5, // Lock detect: -64 Carrier freq detect:on + 0x12, 0xb9, 0x15, 0xc9, // lock detector threshold 0x16, 0x00, 0x17, 0x00, @@ -379,7 +379,6 @@ static struct stv0299_config alps_bsru6_config = { .inittab = alps_bsru6_inittab, .mclk = 88000000UL, .invert = 1, - .enhanced_tuning = 0, .skip_reinit = 0, .lock_output = STV0229_LOCKOUTPUT_1, .volt13_op0_op1 = STV0299_VOLT13_OP1, diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c index 43d6c8268642..bc4ce7559cbe 100644 --- a/drivers/media/dvb/ttpci/budget.c +++ b/drivers/media/dvb/ttpci/budget.c @@ -226,12 +226,14 @@ static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend* fe, int arg) return 0; } -static void lnbp21_init(struct budget* budget) +static int lnbp21_init(struct budget* budget) { u8 buf = 0x00; struct i2c_msg msg = { .addr = 0x08, .flags = 0, .buf = &buf, .len = sizeof(buf) }; - i2c_transfer (&budget->i2c_adap, &msg, 1); + if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) + return -EIO; + return 0; } static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) @@ -273,7 +275,7 @@ static u8 alps_bsru6_inittab[] = { 0x01, 0x15, 0x02, 0x00, 0x03, 0x00, - 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */ + 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */ 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */ 0x06, 0x40, /* DAC not used, set to high impendance mode */ 0x07, 0x00, /* DAC LSB */ @@ -284,7 +286,7 @@ static u8 alps_bsru6_inittab[] = { 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */ 0x10, 0x3f, // AGC2 0x3d 0x11, 0x84, - 0x12, 0xb5, // Lock detect: -64 Carrier freq detect:on + 0x12, 0xb9, 0x15, 0xc9, // lock detector threshold 0x16, 0x00, 0x17, 0x00, @@ -358,7 +360,6 @@ static struct stv0299_config alps_bsru6_config = { .inittab = alps_bsru6_inittab, .mclk = 88000000UL, .invert = 1, - .enhanced_tuning = 0, .skip_reinit = 0, .lock_output = STV0229_LOCKOUTPUT_1, .volt13_op0_op1 = STV0299_VOLT13_OP1, @@ -367,6 +368,79 @@ static struct stv0299_config alps_bsru6_config = { .pll_set = alps_bsru6_pll_set, }; +static u8 alps_bsbe1_inittab[] = { + 0x01, 0x15, + 0x02, 0x30, + 0x03, 0x00, + 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */ + 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */ + 0x06, 0x40, /* DAC not used, set to high impendance mode */ + 0x07, 0x00, /* DAC LSB */ + 0x08, 0x40, /* DiSEqC off, LNB power on OP2/LOCK pin on */ + 0x09, 0x00, /* FIFO */ + 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */ + 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */ + 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */ + 0x10, 0x3f, // AGC2 0x3d + 0x11, 0x84, + 0x12, 0xb9, + 0x15, 0xc9, // lock detector threshold + 0x16, 0x00, + 0x17, 0x00, + 0x18, 0x00, + 0x19, 0x00, + 0x1a, 0x00, + 0x1f, 0x50, + 0x20, 0x00, + 0x21, 0x00, + 0x22, 0x00, + 0x23, 0x00, + 0x28, 0x00, // out imp: normal out type: parallel FEC mode:0 + 0x29, 0x1e, // 1/2 threshold + 0x2a, 0x14, // 2/3 threshold + 0x2b, 0x0f, // 3/4 threshold + 0x2c, 0x09, // 5/6 threshold + 0x2d, 0x05, // 7/8 threshold + 0x2e, 0x01, + 0x31, 0x1f, // test all FECs + 0x32, 0x19, // viterbi and synchro search + 0x33, 0xfc, // rs control + 0x34, 0x93, // error control + 0x0f, 0x92, // 0x80 = inverse AGC + 0xff, 0xff +}; + +static int alps_bsbe1_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters* params) +{ + int ret; + u8 data[4]; + u32 div; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; + + if ((params->frequency < 950000) || (params->frequency > 2150000)) + return -EINVAL; + + div = (params->frequency + (125 - 1)) / 125; // round correctly + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = 0x80 | ((div & 0x18000) >> 10) | 4; + data[3] = (params->frequency > 1530000) ? 0xE0 : 0xE4; + + ret = i2c_transfer(i2c, &msg, 1); + return (ret != 1) ? -EIO : 0; +} + +static struct stv0299_config alps_bsbe1_config = { + .demod_address = 0x68, + .inittab = alps_bsbe1_inittab, + .mclk = 88000000UL, + .invert = 1, + .skip_reinit = 0, + .min_delay_ms = 100, + .set_symbol_rate = alps_bsru6_set_symbol_rate, + .pll_set = alps_bsbe1_pll_set, +}; + static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) { struct budget* budget = (struct budget*) fe->dvb->priv; @@ -500,6 +574,19 @@ static u8 read_pwm(struct budget* budget) static void frontend_init(struct budget *budget) { switch(budget->dev->pci->subsystem_device) { + case 0x1017: + // try the ALPS BSBE1 now + budget->dvb_frontend = stv0299_attach(&alps_bsbe1_config, &budget->i2c_adap); + if (budget->dvb_frontend) { + budget->dvb_frontend->ops->set_voltage = lnbp21_set_voltage; + budget->dvb_frontend->ops->enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage; + if (lnbp21_init(budget)) { + printk("%s: No LNBP21 found!\n", __FUNCTION__); + goto error_out; + } + } + + break; case 0x1003: // Hauppauge/TT Nova budget (stv0299/ALPS BSRU6(tsa5059) OR ves1893/ALPS BSRV2(sp5659)) case 0x1013: // try the ALPS BSRV2 first of all @@ -554,7 +641,10 @@ static void frontend_init(struct budget *budget) if (budget->dvb_frontend) { budget->dvb_frontend->ops->set_voltage = lnbp21_set_voltage; budget->dvb_frontend->ops->enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage; - lnbp21_init(budget); + if (lnbp21_init(budget)) { + printk("%s: No LNBP21 found!\n", __FUNCTION__); + goto error_out; + } break; } } @@ -566,13 +656,17 @@ static void frontend_init(struct budget *budget) budget->dev->pci->subsystem_vendor, budget->dev->pci->subsystem_device); } else { - if (dvb_register_frontend(&budget->dvb_adapter, budget->dvb_frontend)) { - printk("budget: Frontend registration failed!\n"); - if (budget->dvb_frontend->ops->release) - budget->dvb_frontend->ops->release(budget->dvb_frontend); - budget->dvb_frontend = NULL; - } + if (dvb_register_frontend(&budget->dvb_adapter, budget->dvb_frontend)) + goto error_out; } + return; + +error_out: + printk("budget: Frontend registration failed!\n"); + if (budget->dvb_frontend->ops->release) + budget->dvb_frontend->ops->release(budget->dvb_frontend); + budget->dvb_frontend = NULL; + return; } static int budget_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_data *info) @@ -618,6 +712,7 @@ static int budget_detach (struct saa7146_dev* dev) static struct saa7146_extension budget_extension; +MAKE_BUDGET_INFO(ttbs2, "TT-Budget/WinTV-NOVA-S PCI (rev AL/alps bsbe1 lnbp21 frontend)", BUDGET_TT); MAKE_BUDGET_INFO(ttbs, "TT-Budget/WinTV-NOVA-S PCI", BUDGET_TT); MAKE_BUDGET_INFO(ttbc, "TT-Budget/WinTV-NOVA-C PCI", BUDGET_TT); MAKE_BUDGET_INFO(ttbt, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT); @@ -630,6 +725,7 @@ static struct pci_device_id pci_tbl[] = { MAKE_EXTENSION_PCI(ttbc, 0x13c2, 0x1004), MAKE_EXTENSION_PCI(ttbt, 0x13c2, 0x1005), MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013), + MAKE_EXTENSION_PCI(ttbs2, 0x13c2, 0x1017), MAKE_EXTENSION_PCI(ttbs, 0x13c2, 0x1016), MAKE_EXTENSION_PCI(fsacs1,0x1131, 0x4f60), MAKE_EXTENSION_PCI(fsacs0,0x1131, 0x4f61), @@ -642,7 +738,7 @@ MODULE_DEVICE_TABLE(pci, pci_tbl); static struct saa7146_extension budget_extension = { .name = "budget dvb\0", - .flags = 0, + .flags = SAA7146_I2C_SHORT_DELAY, .module = THIS_MODULE, .pci_tbl = pci_tbl, diff --git a/drivers/media/dvb/ttpci/ttpci-eeprom.c b/drivers/media/dvb/ttpci/ttpci-eeprom.c index e9a8457b0727..ac79ef178c05 100644 --- a/drivers/media/dvb/ttpci/ttpci-eeprom.c +++ b/drivers/media/dvb/ttpci/ttpci-eeprom.c @@ -37,6 +37,7 @@ #include <linux/string.h> #include <linux/i2c.h> +#include "ttpci-eeprom.h" #if 1 #define dprintk(x...) do { printk(x); } while (0) diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c index d200ab0ad9e7..fd53d6010502 100644 --- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c +++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c @@ -1198,7 +1198,7 @@ static u8 alps_bsbe1_inittab[] = { 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */ 0x10, 0x3f, // AGC2 0x3d 0x11, 0x84, - 0x12, 0xb5, // Lock detect: -64 Carrier freq detect:on + 0x12, 0xb9, 0x15, 0xc9, // lock detector threshold 0x16, 0x00, 0x17, 0x00, @@ -1240,7 +1240,7 @@ static u8 alps_bsru6_inittab[] = { 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */ 0x10, 0x3f, // AGC2 0x3d 0x11, 0x84, - 0x12, 0xb5, // Lock detect: -64 Carrier freq detect:on + 0x12, 0xb9, 0x15, 0xc9, // lock detector threshold 0x16, 0x00, 0x17, 0x00, @@ -1335,7 +1335,6 @@ static struct stv0299_config alps_stv0299_config = { .inittab = alps_bsru6_inittab, .mclk = 88000000UL, .invert = 1, - .enhanced_tuning = 0, .skip_reinit = 0, .lock_output = STV0229_LOCKOUTPUT_1, .volt13_op0_op1 = STV0299_VOLT13_OP1, diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c index 3d08fc83a754..832d179f26fa 100644 --- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c +++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c @@ -152,7 +152,8 @@ struct ttusb_dec { struct list_head filter_info_list; spinlock_t filter_info_list_lock; - struct input_dev rc_input_dev; + struct input_dev *rc_input_dev; + char rc_phys[64]; int active; /* Loaded successfully */ }; @@ -235,9 +236,9 @@ static void ttusb_dec_handle_irq( struct urb *urb, struct pt_regs *regs) * this should/could be added later ... * for now lets report each signal as a key down and up*/ dprintk("%s:rc signal:%d\n", __FUNCTION__, buffer[4]); - input_report_key(&dec->rc_input_dev,rc_keys[buffer[4]-1],1); - input_report_key(&dec->rc_input_dev,rc_keys[buffer[4]-1],0); - input_sync(&dec->rc_input_dev); + input_report_key(dec->rc_input_dev, rc_keys[buffer[4] - 1], 1); + input_report_key(dec->rc_input_dev, rc_keys[buffer[4] - 1], 0); + input_sync(dec->rc_input_dev); } exit: retval = usb_submit_urb(urb, GFP_ATOMIC); @@ -1181,29 +1182,38 @@ static void ttusb_dec_init_tasklet(struct ttusb_dec *dec) (unsigned long)dec); } -static void ttusb_init_rc( struct ttusb_dec *dec) +static int ttusb_init_rc(struct ttusb_dec *dec) { + struct input_dev *input_dev; u8 b[] = { 0x00, 0x01 }; int i; - init_input_dev(&dec->rc_input_dev); + usb_make_path(dec->udev, dec->rc_phys, sizeof(dec->rc_phys)); + strlcpy(dec->rc_phys, "/input0", sizeof(dec->rc_phys)); - dec->rc_input_dev.name = "ttusb_dec remote control"; - dec->rc_input_dev.evbit[0] = BIT(EV_KEY); - dec->rc_input_dev.keycodesize = sizeof(u16); - dec->rc_input_dev.keycodemax = 0x1a; - dec->rc_input_dev.keycode = rc_keys; + dec->rc_input_dev = input_dev = input_allocate_device(); + if (!input_dev) + return -ENOMEM; + + input_dev->name = "ttusb_dec remote control"; + input_dev->phys = dec->rc_phys; + input_dev->evbit[0] = BIT(EV_KEY); + input_dev->keycodesize = sizeof(u16); + input_dev->keycodemax = 0x1a; + input_dev->keycode = rc_keys; - for (i = 0; i < sizeof(rc_keys)/sizeof(rc_keys[0]); i++) - set_bit(rc_keys[i], dec->rc_input_dev.keybit); + for (i = 0; i < ARRAY_SIZE(rc_keys); i++) + set_bit(rc_keys[i], input_dev->keybit); - input_register_device(&dec->rc_input_dev); + input_register_device(input_dev); - if(usb_submit_urb(dec->irq_urb,GFP_KERNEL)) { + if (usb_submit_urb(dec->irq_urb, GFP_KERNEL)) printk("%s: usb_submit_urb failed\n",__FUNCTION__); - } + /* enable irq pipe */ ttusb_dec_send_command(dec,0xb0,sizeof(b),b,NULL,NULL); + + return 0; } static void ttusb_dec_init_v_pes(struct ttusb_dec *dec) @@ -1513,7 +1523,7 @@ static void ttusb_dec_exit_rc(struct ttusb_dec *dec) * As the irq is submitted after the interface is changed, * this is the best method i figured out. * Any others?*/ - if(dec->interface == TTUSB_DEC_INTERFACE_IN) + if (dec->interface == TTUSB_DEC_INTERFACE_IN) usb_kill_urb(dec->irq_urb); usb_free_urb(dec->irq_urb); @@ -1521,7 +1531,10 @@ static void ttusb_dec_exit_rc(struct ttusb_dec *dec) usb_buffer_free(dec->udev,IRQ_PACKET_SIZE, dec->irq_buffer, dec->irq_dma_handle); - input_unregister_device(&dec->rc_input_dev); + if (dec->rc_input_dev) { + input_unregister_device(dec->rc_input_dev); + dec->rc_input_dev = NULL; + } } @@ -1659,7 +1672,7 @@ static int ttusb_dec_probe(struct usb_interface *intf, ttusb_dec_set_interface(dec, TTUSB_DEC_INTERFACE_IN); - if(enable_rc) + if (enable_rc) ttusb_init_rc(dec); return 0; |