Commit 05cd37de authored by Antti Palosaari's avatar Antti Palosaari Committed by Mauro Carvalho Chehab

[media] anysee: CI/CAM support

Signed-off-by: default avatarAntti Palosaari <crope@iki.fi>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent be94351e
...@@ -130,6 +130,29 @@ static int anysee_wr_reg_mask(struct dvb_usb_device *d, u16 reg, u8 val, ...@@ -130,6 +130,29 @@ static int anysee_wr_reg_mask(struct dvb_usb_device *d, u16 reg, u8 val,
return anysee_write_reg(d, reg, val); 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) static int anysee_get_hw_info(struct dvb_usb_device *d, u8 *id)
{ {
u8 buf[] = {CMD_GET_HW_INFO}; u8 buf[] = {CMD_GET_HW_INFO};
...@@ -157,22 +180,6 @@ static int anysee_ir_ctrl(struct dvb_usb_device *d, u8 onoff) ...@@ -157,22 +180,6 @@ static int anysee_ir_ctrl(struct dvb_usb_device *d, u8 onoff)
return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0); 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 */ /* I2C */
static int anysee_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, static int anysee_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
int num) int num)
...@@ -298,7 +305,7 @@ static struct tda10023_config anysee_tda10023_tda18212_config = { ...@@ -298,7 +305,7 @@ static struct tda10023_config anysee_tda10023_tda18212_config = {
.pll_m = 12, .pll_m = 12,
.pll_p = 3, .pll_p = 3,
.pll_n = 1, .pll_n = 1,
.output_mode = TDA10023_OUTPUT_MODE_PARALLEL_C, .output_mode = TDA10023_OUTPUT_MODE_PARALLEL_B,
.deltaf = 0xba02, .deltaf = 0xba02,
}; };
...@@ -802,11 +809,6 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) ...@@ -802,11 +809,6 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
/* E7 TC */ /* E7 TC */
/* E7 PTC */ /* 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) { if ((state->fe_id ^ dvb_usb_anysee_delsys) == 0) {
/* disable DVB-T demod on IOD[6] */ /* disable DVB-T demod on IOD[6] */
ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 6), ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 6),
...@@ -848,6 +850,8 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) ...@@ -848,6 +850,8 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
adap->fe_adap[state->fe_id].fe->ops.i2c_gate_ctrl = adap->fe_adap[state->fe_id].fe->ops.i2c_gate_ctrl =
anysee_i2c_gate_ctrl; anysee_i2c_gate_ctrl;
state->has_ci = true;
break; break;
case ANYSEE_HW_508S2: /* 19 */ case ANYSEE_HW_508S2: /* 19 */
case ANYSEE_HW_508PS2: /* 22 */ case ANYSEE_HW_508PS2: /* 22 */
...@@ -857,11 +861,6 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) ...@@ -857,11 +861,6 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
if (state->fe_id) if (state->fe_id)
break; break;
/* enable transport stream on IOA[7] */
ret = anysee_wr_reg_mask(adap->dev, REG_IOA, (1 << 7), 0x80);
if (ret)
goto error;
/* enable DVB-S/S2 demod on IOE[5] */ /* enable DVB-S/S2 demod on IOE[5] */
ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 5), 0x20); ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 5), 0x20);
if (ret) if (ret)
...@@ -871,15 +870,12 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) ...@@ -871,15 +870,12 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
adap->fe_adap[0].fe = dvb_attach(stv0900_attach, &anysee_stv0900_config, adap->fe_adap[0].fe = dvb_attach(stv0900_attach, &anysee_stv0900_config,
&adap->dev->i2c_adap, 0); &adap->dev->i2c_adap, 0);
state->has_ci = true;
break; break;
case ANYSEE_HW_508T2C: /* 20 */ case ANYSEE_HW_508T2C: /* 20 */
/* E7 T2C */ /* E7 T2C */
/* enable transport stream on IOA[7] */
ret = anysee_wr_reg_mask(adap->dev, REG_IOA, (1 << 7), 0x80);
if (ret)
goto error;
/* enable DVB-T/T2/C demod on IOE[5] */ /* enable DVB-T/T2/C demod on IOE[5] */
ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 5), 0x20); ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 5), 0x20);
if (ret) if (ret)
...@@ -897,6 +893,8 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) ...@@ -897,6 +893,8 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
&adap->dev->i2c_adap, adap->fe_adap[0].fe); &adap->dev->i2c_adap, adap->fe_adap[0].fe);
} }
state->has_ci = true;
break; break;
} }
...@@ -1042,6 +1040,201 @@ static int anysee_rc_query(struct dvb_usb_device *d) ...@@ -1042,6 +1040,201 @@ static int anysee_rc_query(struct dvb_usb_device *d)
return 0; 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 */ /* DVB USB Driver stuff */
static struct dvb_usb_device_properties anysee_properties; static struct dvb_usb_device_properties anysee_properties;
...@@ -1083,6 +1276,16 @@ static int anysee_probe(struct usb_interface *intf, ...@@ -1083,6 +1276,16 @@ static int anysee_probe(struct usb_interface *intf,
return anysee_init(d); 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[] = { static struct usb_device_id anysee_table[] = {
{ USB_DEVICE(USB_VID_CYPRESS, USB_PID_ANYSEE) }, { USB_DEVICE(USB_VID_CYPRESS, USB_PID_ANYSEE) },
{ USB_DEVICE(USB_VID_AMT, USB_PID_ANYSEE) }, { USB_DEVICE(USB_VID_AMT, USB_PID_ANYSEE) },
...@@ -1160,7 +1363,7 @@ static struct dvb_usb_device_properties anysee_properties = { ...@@ -1160,7 +1363,7 @@ static struct dvb_usb_device_properties anysee_properties = {
static struct usb_driver anysee_driver = { static struct usb_driver anysee_driver = {
.name = "dvb_usb_anysee", .name = "dvb_usb_anysee",
.probe = anysee_probe, .probe = anysee_probe,
.disconnect = dvb_usb_device_exit, .disconnect = anysee_disconnect,
.id_table = anysee_table, .id_table = anysee_table,
}; };
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#define DVB_USB_LOG_PREFIX "anysee" #define DVB_USB_LOG_PREFIX "anysee"
#include "dvb-usb.h" #include "dvb-usb.h"
#include "dvb_ca_en50221.h"
#define deb_info(args...) dprintk(dvb_usb_anysee_debug, 0x01, args) #define deb_info(args...) dprintk(dvb_usb_anysee_debug, 0x01, args)
#define deb_xfer(args...) dprintk(dvb_usb_anysee_debug, 0x02, args) #define deb_xfer(args...) dprintk(dvb_usb_anysee_debug, 0x02, args)
...@@ -54,12 +55,16 @@ enum cmd { ...@@ -54,12 +55,16 @@ enum cmd {
CMD_GET_IR_CODE = 0x41, CMD_GET_IR_CODE = 0x41,
CMD_GET_HW_INFO = 0x19, CMD_GET_HW_INFO = 0x19,
CMD_SMARTCARD = 0x34, CMD_SMARTCARD = 0x34,
CMD_CI = 0x37,
}; };
struct anysee_state { struct anysee_state {
u8 hw; /* PCB ID */ u8 hw; /* PCB ID */
u8 seq; u8 seq;
u8 fe_id:1; /* frondend ID */ 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 */ #define ANYSEE_HW_507T 2 /* E30 */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment