diff --git a/packages/linux/patches/linux-3.2.1-201-add_Anysee_T2C_support-0.1.patch b/packages/linux/patches/linux-3.2.1-201-add_Anysee_T2C_support-0.1.patch new file mode 100644 index 0000000000..429f6900cf --- /dev/null +++ b/packages/linux/patches/linux-3.2.1-201-add_Anysee_T2C_support-0.1.patch @@ -0,0 +1,852 @@ +diff -Naur linux-3.2.1/drivers/media/common/tuners/tda18212.c linux-3.2.1.patch/drivers/media/common/tuners/tda18212.c +--- linux-3.2.1/drivers/media/common/tuners/tda18212.c 2012-01-12 20:42:45.000000000 +0100 ++++ linux-3.2.1.patch/drivers/media/common/tuners/tda18212.c 2012-01-22 14:32:12.474382952 +0100 +@@ -25,6 +25,8 @@ + struct tda18212_priv { + struct tda18212_config *cfg; + struct i2c_adapter *i2c; ++ ++ u32 if_frequency; + }; + + #define dbg(fmt, arg...) \ +@@ -136,12 +138,24 @@ + int ret, i; + u32 if_khz; + u8 buf[9]; ++ #define DVBT_6 0 ++ #define DVBT_7 1 ++ #define DVBT_8 2 ++ #define DVBT2_6 3 ++ #define DVBT2_7 4 ++ #define DVBT2_8 5 ++ #define DVBC_6 6 ++ #define DVBC_8 7 + static const u8 bw_params[][3] = { +- /* 0f 13 23 */ +- { 0xb3, 0x20, 0x03 }, /* DVB-T 6 MHz */ +- { 0xb3, 0x31, 0x01 }, /* DVB-T 7 MHz */ +- { 0xb3, 0x22, 0x01 }, /* DVB-T 8 MHz */ +- { 0x92, 0x53, 0x03 }, /* DVB-C */ ++ /* reg: 0f 13 23 */ ++ [DVBT_6] = { 0xb3, 0x20, 0x03 }, ++ [DVBT_7] = { 0xb3, 0x31, 0x01 }, ++ [DVBT_8] = { 0xb3, 0x22, 0x01 }, ++ [DVBT2_6] = { 0xbc, 0x20, 0x03 }, ++ [DVBT2_7] = { 0xbc, 0x72, 0x03 }, ++ [DVBT2_8] = { 0xbc, 0x22, 0x01 }, ++ [DVBC_6] = { 0x92, 0x50, 0x03 }, ++ [DVBC_8] = { 0x92, 0x53, 0x03 }, + }; + + dbg("delsys=%d RF=%d BW=%d\n", +@@ -155,15 +169,34 @@ + switch (c->bandwidth_hz) { + case 6000000: + if_khz = priv->cfg->if_dvbt_6; +- i = 0; ++ i = DVBT_6; + break; + case 7000000: + if_khz = priv->cfg->if_dvbt_7; +- i = 1; ++ i = DVBT_7; + break; + case 8000000: + if_khz = priv->cfg->if_dvbt_8; +- i = 2; ++ i = DVBT_8; ++ break; ++ default: ++ ret = -EINVAL; ++ goto error; ++ } ++ break; ++ case SYS_DVBT2: ++ switch (c->bandwidth_hz) { ++ case 6000000: ++ if_khz = priv->cfg->if_dvbt2_6; ++ i = DVBT2_6; ++ break; ++ case 7000000: ++ if_khz = priv->cfg->if_dvbt2_7; ++ i = DVBT2_7; ++ break; ++ case 8000000: ++ if_khz = priv->cfg->if_dvbt2_8; ++ i = DVBT2_8; + break; + default: + ret = -EINVAL; +@@ -172,7 +205,7 @@ + break; + case SYS_DVBC_ANNEX_AC: + if_khz = priv->cfg->if_dvbc; +- i = 3; ++ i = DVBC_8; + break; + default: + ret = -EINVAL; +@@ -194,7 +227,7 @@ + buf[0] = 0x02; + buf[1] = bw_params[i][1]; + buf[2] = 0x03; /* default value */ +- buf[3] = if_khz / 50; ++ buf[3] = DIV_ROUND_CLOSEST(if_khz, 50); + buf[4] = ((c->frequency / 1000) >> 16) & 0xff; + buf[5] = ((c->frequency / 1000) >> 8) & 0xff; + buf[6] = ((c->frequency / 1000) >> 0) & 0xff; +@@ -204,6 +237,9 @@ + if (ret) + goto error; + ++ /* actual IF rounded as it is on register */ ++ priv->if_frequency = buf[3] * 50 * 1000; ++ + exit: + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ +@@ -215,6 +251,15 @@ + goto exit; + } + ++static int tda18212_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) ++{ ++ struct tda18212_priv *priv = fe->tuner_priv; ++ ++ *frequency = priv->if_frequency; ++ ++ return 0; ++} ++ + static int tda18212_release(struct dvb_frontend *fe) + { + kfree(fe->tuner_priv); +@@ -234,6 +279,7 @@ + .release = tda18212_release, + + .set_params = tda18212_set_params, ++ .get_if_frequency = tda18212_get_if_frequency, + }; + + struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe, +diff -Naur linux-3.2.1/drivers/media/common/tuners/tda18212.h linux-3.2.1.patch/drivers/media/common/tuners/tda18212.h +--- linux-3.2.1/drivers/media/common/tuners/tda18212.h 2012-01-12 20:42:45.000000000 +0100 ++++ linux-3.2.1.patch/drivers/media/common/tuners/tda18212.h 2012-01-22 14:32:05.694265792 +0100 +@@ -29,6 +29,10 @@ + u16 if_dvbt_6; + u16 if_dvbt_7; + u16 if_dvbt_8; ++ u16 if_dvbt2_5; ++ u16 if_dvbt2_6; ++ u16 if_dvbt2_7; ++ u16 if_dvbt2_8; + u16 if_dvbc; + }; + +diff -Naur linux-3.2.1/drivers/media/dvb/dvb-usb/anysee.c linux-3.2.1.patch/drivers/media/dvb/dvb-usb/anysee.c +--- linux-3.2.1/drivers/media/dvb/dvb-usb/anysee.c 2012-01-12 20:42:45.000000000 +0100 ++++ linux-3.2.1.patch/drivers/media/dvb/dvb-usb/anysee.c 2012-01-22 14:14:31.806583440 +0100 +@@ -41,6 +41,7 @@ + #include "stv0900.h" + #include "stv6110.h" + #include "isl6423.h" ++#include "cxd2820r.h" + + /* debug */ + static int dvb_usb_anysee_debug; +@@ -66,10 +67,12 @@ + if (mutex_lock_interruptible(&anysee_usb_mutex) < 0) + return -EAGAIN; + ++ deb_xfer(">>> "); ++ debug_dump(buf, slen, deb_xfer); ++ + /* We need receive one message more after dvb_usb_generic_rw due + to weird transaction flow, which is 1 x send + 2 x receive. */ + ret = dvb_usb_generic_rw(d, buf, sizeof(buf), buf, sizeof(buf), 0); +- + if (!ret) { + /* receive 2nd answer */ + ret = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev, +@@ -79,7 +82,10 @@ + err("%s: recv bulk message failed: %d", __func__, ret); + else { + deb_xfer("<<< "); +- debug_dump(buf, act_len, deb_xfer); ++ debug_dump(buf, rlen, deb_xfer); ++ ++ if (buf[63] != 0x4f) ++ deb_info("%s: cmd failed\n", __func__); + } + } + +@@ -129,6 +135,29 @@ + return anysee_write_reg(d, reg, val); + } + ++/* read single register with mask */ ++static int anysee_rd_reg_mask(struct dvb_usb_device *d, u16 reg, u8 *val, ++ u8 mask) ++{ ++ int ret, i; ++ u8 tmp; ++ ++ ret = anysee_read_reg(d, reg, &tmp); ++ if (ret) ++ return ret; ++ ++ tmp &= mask; ++ ++ /* find position of the first bit */ ++ for (i = 0; i < 8; i++) { ++ if ((mask >> i) & 0x01) ++ break; ++ } ++ *val = tmp >> i; ++ ++ return 0; ++} ++ + static int anysee_get_hw_info(struct dvb_usb_device *d, u8 *id) + { + u8 buf[] = {CMD_GET_HW_INFO}; +@@ -156,22 +185,6 @@ + return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0); + } + +-static int anysee_init(struct dvb_usb_device *d) +-{ +- int ret; +- /* LED light */ +- ret = anysee_led_ctrl(d, 0x01, 0x03); +- if (ret) +- return ret; +- +- /* enable IR */ +- ret = anysee_ir_ctrl(d, 1); +- if (ret) +- return ret; +- +- return 0; +-} +- + /* I2C */ + static int anysee_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, + int num) +@@ -297,7 +310,7 @@ + .pll_m = 12, + .pll_p = 3, + .pll_n = 1, +- .output_mode = TDA10023_OUTPUT_MODE_PARALLEL_C, ++ .output_mode = TDA10023_OUTPUT_MODE_PARALLEL_B, + .deltaf = 0xba02, + }; + +@@ -309,6 +322,17 @@ + .if_dvbc = 5000, + }; + ++static struct tda18212_config anysee_tda18212_config2 = { ++ .i2c_address = 0x60 /* (0xc0 >> 1) */, ++ .if_dvbt_6 = 3550, ++ .if_dvbt_7 = 3700, ++ .if_dvbt_8 = 4150, ++ .if_dvbt2_6 = 3250, ++ .if_dvbt2_7 = 4000, ++ .if_dvbt2_8 = 4000, ++ .if_dvbc = 5000, ++}; ++ + static struct cx24116_config anysee_cx24116_config = { + .demod_address = (0xaa >> 1), + .mpg_clk_pos_pol = 0x00, +@@ -339,6 +363,18 @@ + .addr = (0x10 >> 1), + }; + ++static struct cxd2820r_config anysee_cxd2820r_config = { ++ .i2c_address = 0x6d, /* (0xda >> 1) */ ++ .ts_mode = 0x38, ++ .if_dvbt_6 = 3550, ++ .if_dvbt_7 = 3700, ++ .if_dvbt_8 = 4150, ++ .if_dvbt2_6 = 3250, ++ .if_dvbt2_7 = 4000, ++ .if_dvbt2_8 = 4000, ++ .if_dvbc = 5000, ++}; ++ + /* + * New USB device strings: Mfr=1, Product=2, SerialNumber=0 + * Manufacturer: AMT.CO.KR +@@ -421,6 +457,14 @@ + * IOA[7] TS 1=enabled + * IOE[5] STV0903 1=enabled + * ++ * E7 T2C VID=1c73 PID=861f HW=20 FW=0.1 AMTCI=0.5 "anysee-E7T2C(LP)" ++ * PCB: 508T2C (rev0.3) ++ * parts: DNOQ44QCH106A(CXD2820R, TDA18212), TDA8024 ++ * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff ++ * IOA=4d IOB=00 IOC=cc IOD=48 IOE=e4 ++ * IOA[7] TS 1=enabled ++ * IOE[5] CXD2820R 1=enabled ++ * + * E7 PTC VID=1c73 PID=861f HW=21 FW=0.1 AMTCI=?? "anysee-E7PTC(LP)" + * PCB: 508PTC (rev0.5) + * parts: ZL10353, TDA10023, DNOD44CDH086A(TDA18212) +@@ -437,7 +481,7 @@ + * IOD[6] ZL10353 1=enabled + * IOE[0] IF 0=enabled + * +- * E7 S2 VID=1c73 PID=861f HW=22 FW=0.1 AMTCI=?? "anysee-E7PS2(LP)" ++ * E7 PS2 VID=1c73 PID=861f HW=22 FW=0.1 AMTCI=?? "anysee-E7PS2(LP)" + * PCB: 508PS2 (rev0.4) + * parts: DNBU10512IST(STV0903, STV6110), ISL6423 + * OEA=80 OEB=00 OEC=03 OED=f7 OEE=ff +@@ -446,6 +490,16 @@ + * IOE[5] STV0903 1=enabled + */ + ++ ++/* external I2C gate used for DNOD44CDH086A(TDA18212) tuner module */ ++static int anysee_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) ++{ ++ struct dvb_usb_adapter *adap = fe->dvb->priv; ++ ++ /* enable / disable tuner access on IOE[4] */ ++ return anysee_wr_reg_mask(adap->dev, REG_IOE, (enable << 4), 0x10); ++} ++ + static int anysee_frontend_ctrl(struct dvb_frontend *fe, int onoff) + { + struct dvb_usb_adapter *adap = fe->dvb->priv; +@@ -577,7 +631,8 @@ + /* detect hardware only once */ + if (adap->fe_adap[0].fe == NULL) { + /* Check which hardware we have. +- * We must do this call two times to get reliable values (hw bug). ++ * We must do this call two times to get reliable values ++ * (hw/fw bug). + */ + ret = anysee_get_hw_info(adap->dev, hw_info); + if (ret) +@@ -606,14 +661,14 @@ + break; + + /* attach demod */ +- adap->fe_adap[0].fe = dvb_attach(mt352_attach, &anysee_mt352_config, +- &adap->dev->i2c_adap); ++ adap->fe_adap[0].fe = dvb_attach(mt352_attach, ++ &anysee_mt352_config, &adap->dev->i2c_adap); + if (adap->fe_adap[0].fe) + break; + + /* attach demod */ +- adap->fe_adap[0].fe = dvb_attach(zl10353_attach, &anysee_zl10353_config, +- &adap->dev->i2c_adap); ++ adap->fe_adap[0].fe = dvb_attach(zl10353_attach, ++ &anysee_zl10353_config, &adap->dev->i2c_adap); + + break; + case ANYSEE_HW_507CD: /* 6 */ +@@ -665,8 +720,8 @@ + goto error; + + /* attach demod */ +- adap->fe_adap[0].fe = dvb_attach(cx24116_attach, &anysee_cx24116_config, +- &adap->dev->i2c_adap); ++ adap->fe_adap[0].fe = dvb_attach(cx24116_attach, ++ &anysee_cx24116_config, &adap->dev->i2c_adap); + + break; + case ANYSEE_HW_507FA: /* 15 */ +@@ -747,17 +802,19 @@ + } + } + ++ /* I2C gate for DNOD44CDH086A(TDA18212) tuner module */ ++ if (tmp == 0xc7) { ++ if (adap->fe_adap[state->fe_id].fe) ++ adap->fe_adap[state->fe_id].fe->ops.i2c_gate_ctrl = ++ anysee_i2c_gate_ctrl; ++ } ++ + break; + case ANYSEE_HW_508TC: /* 18 */ + case ANYSEE_HW_508PTC: /* 21 */ + /* E7 TC */ + /* E7 PTC */ + +- /* enable transport stream on IOA[7] */ +- ret = anysee_wr_reg_mask(adap->dev, REG_IOA, (1 << 7), 0x80); +- if (ret) +- goto error; +- + if ((state->fe_id ^ dvb_usb_anysee_delsys) == 0) { + /* disable DVB-T demod on IOD[6] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 6), +@@ -772,7 +829,8 @@ + goto error; + + /* attach demod */ +- adap->fe_adap[state->fe_id].fe = dvb_attach(tda10023_attach, ++ adap->fe_adap[state->fe_id].fe = ++ dvb_attach(tda10023_attach, + &anysee_tda10023_tda18212_config, + &adap->dev->i2c_adap, 0x48); + } else { +@@ -789,11 +847,19 @@ + goto error; + + /* attach demod */ +- adap->fe_adap[state->fe_id].fe = dvb_attach(zl10353_attach, ++ adap->fe_adap[state->fe_id].fe = ++ dvb_attach(zl10353_attach, + &anysee_zl10353_tda18212_config, + &adap->dev->i2c_adap); + } + ++ /* I2C gate for DNOD44CDH086A(TDA18212) tuner module */ ++ if (adap->fe_adap[state->fe_id].fe) ++ adap->fe_adap[state->fe_id].fe->ops.i2c_gate_ctrl = ++ anysee_i2c_gate_ctrl; ++ ++ state->has_ci = true; ++ + break; + case ANYSEE_HW_508S2: /* 19 */ + case ANYSEE_HW_508PS2: /* 22 */ +@@ -803,19 +869,41 @@ + if (state->fe_id) + break; + +- /* enable transport stream on IOA[7] */ +- ret = anysee_wr_reg_mask(adap->dev, REG_IOA, (1 << 7), 0x80); ++ /* enable DVB-S/S2 demod on IOE[5] */ ++ ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 5), 0x20); + if (ret) + goto error; + +- /* enable DVB-S/S2 demod on IOE[5] */ ++ /* attach demod */ ++ adap->fe_adap[0].fe = dvb_attach(stv0900_attach, ++ &anysee_stv0900_config, &adap->dev->i2c_adap, 0); ++ ++ state->has_ci = true; ++ ++ break; ++ case ANYSEE_HW_508T2C: /* 20 */ ++ /* E7 T2C */ ++ ++ /* enable DVB-T/T2/C demod on IOE[5] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 5), 0x20); + if (ret) + goto error; + +- /* attach demod */ +- adap->fe_adap[0].fe = dvb_attach(stv0900_attach, &anysee_stv0900_config, +- &adap->dev->i2c_adap, 0); ++ if (state->fe_id == 0) { ++ /* DVB-T/T2 */ ++ adap->fe_adap[state->fe_id].fe = ++ dvb_attach(cxd2820r_attach, ++ &anysee_cxd2820r_config, ++ &adap->dev->i2c_adap, NULL); ++ } else { ++ /* DVB-C */ ++ adap->fe_adap[state->fe_id].fe = ++ dvb_attach(cxd2820r_attach, ++ &anysee_cxd2820r_config, ++ &adap->dev->i2c_adap, adap->fe_adap[0].fe); ++ } ++ ++ state->has_ci = true; + + break; + } +@@ -842,24 +930,26 @@ + /* E30 */ + + /* attach tuner */ +- fe = dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, (0xc2 >> 1), +- NULL, DVB_PLL_THOMSON_DTT7579); ++ fe = dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, ++ (0xc2 >> 1), NULL, DVB_PLL_THOMSON_DTT7579); + + break; + case ANYSEE_HW_507CD: /* 6 */ + /* E30 Plus */ + + /* attach tuner */ +- fe = dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, (0xc2 >> 1), +- &adap->dev->i2c_adap, DVB_PLL_THOMSON_DTT7579); ++ fe = dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, ++ (0xc2 >> 1), &adap->dev->i2c_adap, ++ DVB_PLL_THOMSON_DTT7579); + + break; + case ANYSEE_HW_507DC: /* 10 */ + /* E30 C Plus */ + + /* attach tuner */ +- fe = dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, (0xc0 >> 1), +- &adap->dev->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A); ++ fe = dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, ++ (0xc0 >> 1), &adap->dev->i2c_adap, ++ DVB_PLL_SAMSUNG_DTOS403IH102A); + + break; + case ANYSEE_HW_507SI: /* 11 */ +@@ -877,22 +967,12 @@ + /* Try first attach TDA18212 silicon tuner on IOE[4], if that + * fails attach old simple PLL. */ + +- /* enable tuner on IOE[4] */ +- ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 4), 0x10); +- if (ret) +- goto error; +- + /* attach tuner */ + fe = dvb_attach(tda18212_attach, adap->fe_adap[state->fe_id].fe, + &adap->dev->i2c_adap, &anysee_tda18212_config); + if (fe) + break; + +- /* disable tuner on IOE[4] */ +- ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (0 << 4), 0x10); +- if (ret) +- goto error; +- + /* attach tuner */ + fe = dvb_attach(dvb_pll_attach, adap->fe_adap[state->fe_id].fe, + (0xc0 >> 1), &adap->dev->i2c_adap, +@@ -904,11 +984,6 @@ + /* E7 TC */ + /* E7 PTC */ + +- /* enable tuner on IOE[4] */ +- ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 4), 0x10); +- if (ret) +- goto error; +- + /* attach tuner */ + fe = dvb_attach(tda18212_attach, adap->fe_adap[state->fe_id].fe, + &adap->dev->i2c_adap, &anysee_tda18212_config); +@@ -930,6 +1005,15 @@ + } + + break; ++ ++ case ANYSEE_HW_508T2C: /* 20 */ ++ /* E7 T2C */ ++ ++ /* attach tuner */ ++ fe = dvb_attach(tda18212_attach, adap->fe_adap[state->fe_id].fe, ++ &adap->dev->i2c_adap, &anysee_tda18212_config2); ++ ++ break; + default: + fe = NULL; + } +@@ -939,7 +1023,6 @@ + else + ret = -ENODEV; + +-error: + return ret; + } + +@@ -969,6 +1052,201 @@ + return 0; + } + ++static int anysee_ci_read_attribute_mem(struct dvb_ca_en50221 *ci, int slot, ++ int addr) ++{ ++ struct dvb_usb_device *d = ci->data; ++ int ret; ++ u8 buf[] = {CMD_CI, 0x02, 0x40 | addr >> 8, addr & 0xff, 0x00, 1}; ++ u8 val; ++ ++ ret = anysee_ctrl_msg(d, buf, sizeof(buf), &val, 1); ++ if (ret) ++ return ret; ++ ++ return val; ++} ++ ++static int anysee_ci_write_attribute_mem(struct dvb_ca_en50221 *ci, int slot, ++ int addr, u8 val) ++{ ++ struct dvb_usb_device *d = ci->data; ++ int ret; ++ u8 buf[] = {CMD_CI, 0x03, 0x40 | addr >> 8, addr & 0xff, 0x00, 1, val}; ++ ++ ret = anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static int anysee_ci_read_cam_control(struct dvb_ca_en50221 *ci, int slot, ++ u8 addr) ++{ ++ struct dvb_usb_device *d = ci->data; ++ int ret; ++ u8 buf[] = {CMD_CI, 0x04, 0x40, addr, 0x00, 1}; ++ u8 val; ++ ++ ret = anysee_ctrl_msg(d, buf, sizeof(buf), &val, 1); ++ if (ret) ++ return ret; ++ ++ return val; ++} ++ ++static int anysee_ci_write_cam_control(struct dvb_ca_en50221 *ci, int slot, ++ u8 addr, u8 val) ++{ ++ struct dvb_usb_device *d = ci->data; ++ int ret; ++ u8 buf[] = {CMD_CI, 0x05, 0x40, addr, 0x00, 1, val}; ++ ++ ret = anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static int anysee_ci_slot_reset(struct dvb_ca_en50221 *ci, int slot) ++{ ++ struct dvb_usb_device *d = ci->data; ++ int ret; ++ struct anysee_state *state = d->priv; ++ ++ state->ci_cam_ready = jiffies + msecs_to_jiffies(1000); ++ ++ ret = anysee_wr_reg_mask(d, REG_IOA, (0 << 7), 0x80); ++ if (ret) ++ return ret; ++ ++ msleep(300); ++ ++ ret = anysee_wr_reg_mask(d, REG_IOA, (1 << 7), 0x80); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static int anysee_ci_slot_shutdown(struct dvb_ca_en50221 *ci, int slot) ++{ ++ struct dvb_usb_device *d = ci->data; ++ int ret; ++ ++ ret = anysee_wr_reg_mask(d, REG_IOA, (0 << 7), 0x80); ++ if (ret) ++ return ret; ++ ++ msleep(30); ++ ++ ret = anysee_wr_reg_mask(d, REG_IOA, (1 << 7), 0x80); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static int anysee_ci_slot_ts_enable(struct dvb_ca_en50221 *ci, int slot) ++{ ++ struct dvb_usb_device *d = ci->data; ++ int ret; ++ ++ ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 1), 0x02); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static int anysee_ci_poll_slot_status(struct dvb_ca_en50221 *ci, int slot, ++ int open) ++{ ++ struct dvb_usb_device *d = ci->data; ++ struct anysee_state *state = d->priv; ++ int ret; ++ u8 tmp; ++ ++ ret = anysee_rd_reg_mask(d, REG_IOC, &tmp, 0x40); ++ if (ret) ++ return ret; ++ ++ if (tmp == 0) { ++ ret = DVB_CA_EN50221_POLL_CAM_PRESENT; ++ if (time_after(jiffies, state->ci_cam_ready)) ++ ret |= DVB_CA_EN50221_POLL_CAM_READY; ++ } ++ ++ return ret; ++} ++ ++static int anysee_ci_init(struct dvb_usb_device *d) ++{ ++ struct anysee_state *state = d->priv; ++ int ret; ++ ++ state->ci.owner = THIS_MODULE; ++ state->ci.read_attribute_mem = anysee_ci_read_attribute_mem; ++ state->ci.write_attribute_mem = anysee_ci_write_attribute_mem; ++ state->ci.read_cam_control = anysee_ci_read_cam_control; ++ state->ci.write_cam_control = anysee_ci_write_cam_control; ++ state->ci.slot_reset = anysee_ci_slot_reset; ++ state->ci.slot_shutdown = anysee_ci_slot_shutdown; ++ state->ci.slot_ts_enable = anysee_ci_slot_ts_enable; ++ state->ci.poll_slot_status = anysee_ci_poll_slot_status; ++ state->ci.data = d; ++ ++ ret = anysee_wr_reg_mask(d, REG_IOA, (1 << 7), 0x80); ++ if (ret) ++ return ret; ++ ++ ret = dvb_ca_en50221_init(&d->adapter[0].dvb_adap, &state->ci, 0, 1); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static void anysee_ci_release(struct dvb_usb_device *d) ++{ ++ struct anysee_state *state = d->priv; ++ ++ /* detach CI */ ++ if (state->has_ci) ++ dvb_ca_en50221_release(&state->ci); ++ ++ return; ++} ++ ++static int anysee_init(struct dvb_usb_device *d) ++{ ++ struct anysee_state *state = d->priv; ++ int ret; ++ ++ /* LED light */ ++ ret = anysee_led_ctrl(d, 0x01, 0x03); ++ if (ret) ++ return ret; ++ ++ /* enable IR */ ++ ret = anysee_ir_ctrl(d, 1); ++ if (ret) ++ return ret; ++ ++ /* attach CI */ ++ if (state->has_ci) { ++ ret = anysee_ci_init(d); ++ if (ret) { ++ state->has_ci = false; ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ + /* DVB USB Driver stuff */ + static struct dvb_usb_device_properties anysee_properties; + +@@ -1010,6 +1288,16 @@ + return anysee_init(d); + } + ++static void anysee_disconnect(struct usb_interface *intf) ++{ ++ struct dvb_usb_device *d = usb_get_intfdata(intf); ++ ++ anysee_ci_release(d); ++ dvb_usb_device_exit(intf); ++ ++ return; ++} ++ + static struct usb_device_id anysee_table[] = { + { USB_DEVICE(USB_VID_CYPRESS, USB_PID_ANYSEE) }, + { USB_DEVICE(USB_VID_AMT, USB_PID_ANYSEE) }, +@@ -1029,7 +1317,7 @@ + { + .num_frontends = 2, + .frontend_ctrl = anysee_frontend_ctrl, +- .fe = {{ ++ .fe = { { + .streaming_ctrl = anysee_streaming_ctrl, + .frontend_attach = anysee_frontend_attach, + .tuner_attach = anysee_tuner_attach, +@@ -1057,7 +1345,7 @@ + } + } + }, +- }}, ++ } }, + } + }, + +@@ -1087,7 +1375,7 @@ + static struct usb_driver anysee_driver = { + .name = "dvb_usb_anysee", + .probe = anysee_probe, +- .disconnect = dvb_usb_device_exit, ++ .disconnect = anysee_disconnect, + .id_table = anysee_table, + }; + +diff -Naur linux-3.2.1/drivers/media/dvb/dvb-usb/anysee.h linux-3.2.1.patch/drivers/media/dvb/dvb-usb/anysee.h +--- linux-3.2.1/drivers/media/dvb/dvb-usb/anysee.h 2012-01-12 20:42:45.000000000 +0100 ++++ linux-3.2.1.patch/drivers/media/dvb/dvb-usb/anysee.h 2012-01-22 14:14:20.107382315 +0100 +@@ -36,6 +36,7 @@ + + #define DVB_USB_LOG_PREFIX "anysee" + #include "dvb-usb.h" ++#include "dvb_ca_en50221.h" + + #define deb_info(args...) dprintk(dvb_usb_anysee_debug, 0x01, args) + #define deb_xfer(args...) dprintk(dvb_usb_anysee_debug, 0x02, args) +@@ -54,12 +55,16 @@ + CMD_GET_IR_CODE = 0x41, + CMD_GET_HW_INFO = 0x19, + CMD_SMARTCARD = 0x34, ++ CMD_CI = 0x37, + }; + + struct anysee_state { + u8 hw; /* PCB ID */ + u8 seq; + u8 fe_id:1; /* frondend ID */ ++ u8 has_ci:1; ++ struct dvb_ca_en50221 ci; ++ unsigned long ci_cam_ready; /* jiffies */ + }; + + #define ANYSEE_HW_507T 2 /* E30 */ +@@ -69,6 +74,7 @@ + #define ANYSEE_HW_507FA 15 /* E30 Combo Plus / E30 C Plus */ + #define ANYSEE_HW_508TC 18 /* E7 TC */ + #define ANYSEE_HW_508S2 19 /* E7 S2 */ ++#define ANYSEE_HW_508T2C 20 /* E7 T2C */ + #define ANYSEE_HW_508PTC 21 /* E7 PTC Plus */ + #define ANYSEE_HW_508PS2 22 /* E7 PS2 Plus */ + +diff -Naur linux-3.2.1/drivers/media/dvb/dvb-usb/Kconfig linux-3.2.1.patch/drivers/media/dvb/dvb-usb/Kconfig +--- linux-3.2.1/drivers/media/dvb/dvb-usb/Kconfig 2012-01-12 20:42:45.000000000 +0100 ++++ linux-3.2.1.patch/drivers/media/dvb/dvb-usb/Kconfig 2012-01-22 14:14:11.662237130 +0100 +@@ -311,6 +311,7 @@ + select DVB_STV0900 if !DVB_FE_CUSTOMISE + select DVB_STV6110 if !DVB_FE_CUSTOMISE + select DVB_ISL6423 if !DVB_FE_CUSTOMISE ++ select DVB_CXD2820R if !DVB_FE_CUSTOMISE + help + Say Y here to support the Anysee E30, Anysee E30 Plus or + Anysee E30 C Plus DVB USB2.0 receiver.