mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-26 10:49:33 +00:00
[media] Add CI support to az6007 driver
This patch add CI support to az6007 driver. Signed-off-by: Jose Alberto Reguero <jareguero@telefonica.net> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
parent
266e8ae37d
commit
962f8f67e4
1 changed files with 376 additions and 1 deletions
|
@ -54,6 +54,7 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
|
|||
|
||||
struct az6007_device_state {
|
||||
struct mutex mutex;
|
||||
struct mutex ca_mutex;
|
||||
struct dvb_ca_en50221 ca;
|
||||
unsigned warm:1;
|
||||
int (*gate_ctrl) (struct dvb_frontend *, int);
|
||||
|
@ -218,6 +219,371 @@ static int az6007_rc_query(struct dvb_usb_device *d)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int az6007_ci_read_attribute_mem(struct dvb_ca_en50221 *ca,
|
||||
int slot,
|
||||
int address)
|
||||
{
|
||||
struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
|
||||
struct az6007_device_state *state = (struct az6007_device_state *)d->priv;
|
||||
|
||||
int ret;
|
||||
u8 req;
|
||||
u16 value;
|
||||
u16 index;
|
||||
int blen;
|
||||
u8 *b;
|
||||
|
||||
if (slot != 0)
|
||||
return -EINVAL;
|
||||
|
||||
b = kmalloc(12, GFP_KERNEL);
|
||||
if (!b)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_lock(&state->ca_mutex);
|
||||
|
||||
req = 0xC1;
|
||||
value = address;
|
||||
index = 0;
|
||||
blen = 1;
|
||||
|
||||
ret = az6007_read(d, req, value, index, b, blen);
|
||||
if (ret < 0) {
|
||||
warn("usb in operation failed. (%d)", ret);
|
||||
ret = -EINVAL;
|
||||
} else {
|
||||
ret = b[0];
|
||||
}
|
||||
|
||||
mutex_unlock(&state->ca_mutex);
|
||||
kfree(b);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int az6007_ci_write_attribute_mem(struct dvb_ca_en50221 *ca,
|
||||
int slot,
|
||||
int address,
|
||||
u8 value)
|
||||
{
|
||||
struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
|
||||
struct az6007_device_state *state = (struct az6007_device_state *)d->priv;
|
||||
|
||||
int ret;
|
||||
u8 req;
|
||||
u16 value1;
|
||||
u16 index;
|
||||
int blen;
|
||||
|
||||
deb_info("%s %d", __func__, slot);
|
||||
if (slot != 0)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&state->ca_mutex);
|
||||
req = 0xC2;
|
||||
value1 = address;
|
||||
index = value;
|
||||
blen = 0;
|
||||
|
||||
ret = az6007_write(d, req, value1, index, NULL, blen);
|
||||
if (ret != 0)
|
||||
warn("usb out operation failed. (%d)", ret);
|
||||
|
||||
mutex_unlock(&state->ca_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int az6007_ci_read_cam_control(struct dvb_ca_en50221 *ca,
|
||||
int slot,
|
||||
u8 address)
|
||||
{
|
||||
struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
|
||||
struct az6007_device_state *state = (struct az6007_device_state *)d->priv;
|
||||
|
||||
int ret;
|
||||
u8 req;
|
||||
u16 value;
|
||||
u16 index;
|
||||
int blen;
|
||||
u8 *b;
|
||||
|
||||
if (slot != 0)
|
||||
return -EINVAL;
|
||||
|
||||
b = kmalloc(12, GFP_KERNEL);
|
||||
if (!b)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_lock(&state->ca_mutex);
|
||||
|
||||
req = 0xC3;
|
||||
value = address;
|
||||
index = 0;
|
||||
blen = 2;
|
||||
|
||||
ret = az6007_read(d, req, value, index, b, blen);
|
||||
if (ret < 0) {
|
||||
warn("usb in operation failed. (%d)", ret);
|
||||
ret = -EINVAL;
|
||||
} else {
|
||||
if (b[0] == 0)
|
||||
warn("Read CI IO error");
|
||||
|
||||
ret = b[1];
|
||||
deb_info("read cam data = %x from 0x%x", b[1], value);
|
||||
}
|
||||
|
||||
mutex_unlock(&state->ca_mutex);
|
||||
kfree(b);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int az6007_ci_write_cam_control(struct dvb_ca_en50221 *ca,
|
||||
int slot,
|
||||
u8 address,
|
||||
u8 value)
|
||||
{
|
||||
struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
|
||||
struct az6007_device_state *state = (struct az6007_device_state *)d->priv;
|
||||
|
||||
int ret;
|
||||
u8 req;
|
||||
u16 value1;
|
||||
u16 index;
|
||||
int blen;
|
||||
|
||||
if (slot != 0)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&state->ca_mutex);
|
||||
req = 0xC4;
|
||||
value1 = address;
|
||||
index = value;
|
||||
blen = 0;
|
||||
|
||||
ret = az6007_write(d, req, value1, index, NULL, blen);
|
||||
if (ret != 0) {
|
||||
warn("usb out operation failed. (%d)", ret);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
failed:
|
||||
mutex_unlock(&state->ca_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int CI_CamReady(struct dvb_ca_en50221 *ca, int slot)
|
||||
{
|
||||
struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
|
||||
|
||||
int ret;
|
||||
u8 req;
|
||||
u16 value;
|
||||
u16 index;
|
||||
int blen;
|
||||
u8 *b;
|
||||
|
||||
b = kmalloc(12, GFP_KERNEL);
|
||||
if (!b)
|
||||
return -ENOMEM;
|
||||
|
||||
req = 0xC8;
|
||||
value = 0;
|
||||
index = 0;
|
||||
blen = 1;
|
||||
|
||||
ret = az6007_read(d, req, value, index, b, blen);
|
||||
if (ret < 0) {
|
||||
warn("usb in operation failed. (%d)", ret);
|
||||
ret = -EIO;
|
||||
} else{
|
||||
ret = b[0];
|
||||
}
|
||||
kfree(b);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int az6007_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot)
|
||||
{
|
||||
struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
|
||||
struct az6007_device_state *state = (struct az6007_device_state *)d->priv;
|
||||
|
||||
int ret, i;
|
||||
u8 req;
|
||||
u16 value;
|
||||
u16 index;
|
||||
int blen;
|
||||
|
||||
mutex_lock(&state->ca_mutex);
|
||||
|
||||
req = 0xC6;
|
||||
value = 1;
|
||||
index = 0;
|
||||
blen = 0;
|
||||
|
||||
ret = az6007_write(d, req, value, index, NULL, blen);
|
||||
if (ret != 0) {
|
||||
warn("usb out operation failed. (%d)", ret);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
msleep(500);
|
||||
req = 0xC6;
|
||||
value = 0;
|
||||
index = 0;
|
||||
blen = 0;
|
||||
|
||||
ret = az6007_write(d, req, value, index, NULL, blen);
|
||||
if (ret != 0) {
|
||||
warn("usb out operation failed. (%d)", ret);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
for (i = 0; i < 15; i++) {
|
||||
msleep(100);
|
||||
|
||||
if (CI_CamReady(ca, slot)) {
|
||||
deb_info("CAM Ready");
|
||||
break;
|
||||
}
|
||||
}
|
||||
msleep(5000);
|
||||
|
||||
failed:
|
||||
mutex_unlock(&state->ca_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int az6007_ci_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int az6007_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
|
||||
{
|
||||
struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
|
||||
struct az6007_device_state *state = (struct az6007_device_state *)d->priv;
|
||||
|
||||
int ret;
|
||||
u8 req;
|
||||
u16 value;
|
||||
u16 index;
|
||||
int blen;
|
||||
|
||||
deb_info("%s", __func__);
|
||||
mutex_lock(&state->ca_mutex);
|
||||
req = 0xC7;
|
||||
value = 1;
|
||||
index = 0;
|
||||
blen = 0;
|
||||
|
||||
ret = az6007_write(d, req, value, index, NULL, blen);
|
||||
if (ret != 0) {
|
||||
warn("usb out operation failed. (%d)", ret);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
failed:
|
||||
mutex_unlock(&state->ca_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int az6007_ci_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
|
||||
{
|
||||
struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
|
||||
struct az6007_device_state *state = (struct az6007_device_state *)d->priv;
|
||||
int ret;
|
||||
u8 req;
|
||||
u16 value;
|
||||
u16 index;
|
||||
int blen;
|
||||
u8 *b;
|
||||
|
||||
b = kmalloc(12, GFP_KERNEL);
|
||||
if (!b)
|
||||
return -ENOMEM;
|
||||
mutex_lock(&state->ca_mutex);
|
||||
|
||||
req = 0xC5;
|
||||
value = 0;
|
||||
index = 0;
|
||||
blen = 1;
|
||||
|
||||
ret = az6007_read(d, req, value, index, b, blen);
|
||||
if (ret < 0) {
|
||||
warn("usb in operation failed. (%d)", ret);
|
||||
ret = -EIO;
|
||||
} else
|
||||
ret = 0;
|
||||
|
||||
if (!ret && b[0] == 1) {
|
||||
ret = DVB_CA_EN50221_POLL_CAM_PRESENT |
|
||||
DVB_CA_EN50221_POLL_CAM_READY;
|
||||
}
|
||||
|
||||
mutex_unlock(&state->ca_mutex);
|
||||
kfree(b);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void az6007_ci_uninit(struct dvb_usb_device *d)
|
||||
{
|
||||
struct az6007_device_state *state;
|
||||
|
||||
deb_info("%s", __func__);
|
||||
|
||||
if (NULL == d)
|
||||
return;
|
||||
|
||||
state = (struct az6007_device_state *)d->priv;
|
||||
if (NULL == state)
|
||||
return;
|
||||
|
||||
if (NULL == state->ca.data)
|
||||
return;
|
||||
|
||||
dvb_ca_en50221_release(&state->ca);
|
||||
|
||||
memset(&state->ca, 0, sizeof(state->ca));
|
||||
}
|
||||
|
||||
|
||||
static int az6007_ci_init(struct dvb_usb_adapter *a)
|
||||
{
|
||||
struct dvb_usb_device *d = a->dev;
|
||||
struct az6007_device_state *state = (struct az6007_device_state *)d->priv;
|
||||
int ret;
|
||||
|
||||
deb_info("%s", __func__);
|
||||
|
||||
mutex_init(&state->ca_mutex);
|
||||
|
||||
state->ca.owner = THIS_MODULE;
|
||||
state->ca.read_attribute_mem = az6007_ci_read_attribute_mem;
|
||||
state->ca.write_attribute_mem = az6007_ci_write_attribute_mem;
|
||||
state->ca.read_cam_control = az6007_ci_read_cam_control;
|
||||
state->ca.write_cam_control = az6007_ci_write_cam_control;
|
||||
state->ca.slot_reset = az6007_ci_slot_reset;
|
||||
state->ca.slot_shutdown = az6007_ci_slot_shutdown;
|
||||
state->ca.slot_ts_enable = az6007_ci_slot_ts_enable;
|
||||
state->ca.poll_slot_status = az6007_ci_poll_slot_status;
|
||||
state->ca.data = d;
|
||||
|
||||
ret = dvb_ca_en50221_init(&a->dvb_adap,
|
||||
&state->ca,
|
||||
0, /* flags */
|
||||
1);/* n_slots */
|
||||
if (ret != 0) {
|
||||
err("Cannot initialize CI: Error %d.", ret);
|
||||
memset(&state->ca, 0, sizeof(state->ca));
|
||||
return ret;
|
||||
}
|
||||
|
||||
deb_info("CI initialized.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int az6007_read_mac_addr(struct dvb_usb_device *d, u8 mac[6])
|
||||
{
|
||||
struct az6007_device_state *st = d->priv;
|
||||
|
@ -249,6 +615,8 @@ static int az6007_frontend_attach(struct dvb_usb_adapter *adap)
|
|||
st->gate_ctrl = adap->fe_adap[0].fe->ops.i2c_gate_ctrl;
|
||||
adap->fe_adap[0].fe->ops.i2c_gate_ctrl = drxk_gate_ctrl;
|
||||
|
||||
az6007_ci_init(adap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -471,6 +839,13 @@ int az6007_identify_state(struct usb_device *udev,
|
|||
|
||||
static struct dvb_usb_device_properties az6007_properties;
|
||||
|
||||
static void az6007_usb_disconnect(struct usb_interface *intf)
|
||||
{
|
||||
struct dvb_usb_device *d = usb_get_intfdata(intf);
|
||||
az6007_ci_uninit(d);
|
||||
dvb_usb_device_exit(intf);
|
||||
}
|
||||
|
||||
static int az6007_usb_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
|
@ -546,7 +921,7 @@ static struct dvb_usb_device_properties az6007_properties = {
|
|||
static struct usb_driver az6007_usb_driver = {
|
||||
.name = "dvb_usb_az6007",
|
||||
.probe = az6007_usb_probe,
|
||||
.disconnect = dvb_usb_device_exit,
|
||||
.disconnect = az6007_usb_disconnect,
|
||||
.id_table = az6007_usb_table,
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue