aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/dvb/firewire/firedtv-avc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/dvb/firewire/firedtv-avc.c')
-rw-r--r--drivers/media/dvb/firewire/firedtv-avc.c437
1 files changed, 255 insertions, 182 deletions
diff --git a/drivers/media/dvb/firewire/firedtv-avc.c b/drivers/media/dvb/firewire/firedtv-avc.c
index 50c42a4..8f31054 100644
--- a/drivers/media/dvb/firewire/firedtv-avc.c
+++ b/drivers/media/dvb/firewire/firedtv-avc.c
@@ -74,7 +74,6 @@
#define EN50221_TAG_CA_INFO 0x9f8031
struct avc_command_frame {
- int length;
u8 ctype;
u8 subunit;
u8 opcode;
@@ -82,7 +81,6 @@ struct avc_command_frame {
};
struct avc_response_frame {
- int length;
u8 response;
u8 subunit;
u8 opcode;
@@ -202,78 +200,65 @@ static void debug_pmt(char *msg, int length)
16, 1, msg, length, false);
}
-static int __avc_write(struct firedtv *fdtv,
- const struct avc_command_frame *c, struct avc_response_frame *r)
+static int avc_write(struct firedtv *fdtv)
{
int err, retry;
- if (r)
- fdtv->avc_reply_received = false;
+ fdtv->avc_reply_received = false;
for (retry = 0; retry < 6; retry++) {
if (unlikely(avc_debug))
- debug_fcp(&c->ctype, c->length);
+ debug_fcp(fdtv->avc_data, fdtv->avc_data_length);
err = fdtv->backend->write(fdtv, FCP_COMMAND_REGISTER,
- (void *)&c->ctype, c->length);
+ fdtv->avc_data, fdtv->avc_data_length);
if (err) {
- fdtv->avc_reply_received = true;
dev_err(fdtv->device, "FCP command write failed\n");
+
return err;
}
- if (!r)
- return 0;
-
/*
* AV/C specs say that answers should be sent within 150 ms.
* Time out after 200 ms.
*/
if (wait_event_timeout(fdtv->avc_wait,
fdtv->avc_reply_received,
- msecs_to_jiffies(200)) != 0) {
- r->length = fdtv->response_length;
- memcpy(&r->response, fdtv->response, r->length);
-
+ msecs_to_jiffies(200)) != 0)
return 0;
- }
}
dev_err(fdtv->device, "FCP response timed out\n");
+
return -ETIMEDOUT;
}
-static int avc_write(struct firedtv *fdtv,
- const struct avc_command_frame *c, struct avc_response_frame *r)
+static bool is_register_rc(struct avc_response_frame *r)
{
- int ret;
-
- if (mutex_lock_interruptible(&fdtv->avc_mutex))
- return -EINTR;
-
- ret = __avc_write(fdtv, c, r);
-
- mutex_unlock(&fdtv->avc_mutex);
- return ret;
+ return r->opcode == AVC_OPCODE_VENDOR &&
+ r->operand[0] == SFE_VENDOR_DE_COMPANYID_0 &&
+ r->operand[1] == SFE_VENDOR_DE_COMPANYID_1 &&
+ r->operand[2] == SFE_VENDOR_DE_COMPANYID_2 &&
+ r->operand[3] == SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL;
}
int avc_recv(struct firedtv *fdtv, void *data, size_t length)
{
- struct avc_response_frame *r =
- data - offsetof(struct avc_response_frame, response);
+ struct avc_response_frame *r = data;
if (unlikely(avc_debug))
debug_fcp(data, length);
- if (length >= 8 &&
- r->operand[0] == SFE_VENDOR_DE_COMPANYID_0 &&
- r->operand[1] == SFE_VENDOR_DE_COMPANYID_1 &&
- r->operand[2] == SFE_VENDOR_DE_COMPANYID_2 &&
- r->operand[3] == SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL) {
- if (r->response == AVC_RESPONSE_CHANGED) {
- fdtv_handle_rc(fdtv,
- r->operand[4] << 8 | r->operand[5]);
+ if (length >= 8 && is_register_rc(r)) {
+ switch (r->response) {
+ case AVC_RESPONSE_CHANGED:
+ fdtv_handle_rc(fdtv, r->operand[4] << 8 | r->operand[5]);
schedule_work(&fdtv->remote_ctrl_work);
- } else if (r->response != AVC_RESPONSE_INTERIM) {
+ break;
+ case AVC_RESPONSE_INTERIM:
+ if (is_register_rc((void *)fdtv->avc_data))
+ goto wake;
+ break;
+ default:
dev_info(fdtv->device,
"remote control result = %d\n", r->response);
}
@@ -285,9 +270,9 @@ int avc_recv(struct firedtv *fdtv, void *data, size_t length)
return -EIO;
}
- memcpy(fdtv->response, data, length);
- fdtv->response_length = length;
-
+ memcpy(fdtv->avc_data, data, length);
+ fdtv->avc_data_length = length;
+wake:
fdtv->avc_reply_received = true;
wake_up(&fdtv->avc_wait);
@@ -319,9 +304,10 @@ static int add_pid_filter(struct firedtv *fdtv, u8 *operand)
* (not supported by the AVC standard)
*/
static void avc_tuner_tuneqpsk(struct firedtv *fdtv,
- struct dvb_frontend_parameters *params,
- struct avc_command_frame *c)
+ struct dvb_frontend_parameters *params)
{
+ struct avc_command_frame *c = (void *)fdtv->avc_data;
+
c->opcode = AVC_OPCODE_VENDOR;
c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
@@ -370,16 +356,17 @@ static void avc_tuner_tuneqpsk(struct firedtv *fdtv,
c->operand[13] = 0x1;
c->operand[14] = 0xff;
c->operand[15] = 0xff;
- c->length = 20;
+ fdtv->avc_data_length = 20;
} else {
- c->length = 16;
+ fdtv->avc_data_length = 16;
}
}
static void avc_tuner_dsd_dvb_c(struct firedtv *fdtv,
- struct dvb_frontend_parameters *params,
- struct avc_command_frame *c)
+ struct dvb_frontend_parameters *params)
{
+ struct avc_command_frame *c = (void *)fdtv->avc_data;
+
c->opcode = AVC_OPCODE_DSD;
c->operand[0] = 0; /* source plug */
@@ -441,14 +428,15 @@ static void avc_tuner_dsd_dvb_c(struct firedtv *fdtv,
c->operand[21] = 0x00;
/* Add PIDs to filter */
- c->length = ALIGN(22 + add_pid_filter(fdtv, &c->operand[22]) + 3, 4);
+ fdtv->avc_data_length =
+ ALIGN(22 + add_pid_filter(fdtv, &c->operand[22]) + 3, 4);
}
static void avc_tuner_dsd_dvb_t(struct firedtv *fdtv,
- struct dvb_frontend_parameters *params,
- struct avc_command_frame *c)
+ struct dvb_frontend_parameters *params)
{
struct dvb_ofdm_parameters *ofdm = &params->u.ofdm;
+ struct avc_command_frame *c = (void *)fdtv->avc_data;
c->opcode = AVC_OPCODE_DSD;
@@ -544,15 +532,18 @@ static void avc_tuner_dsd_dvb_t(struct firedtv *fdtv,
c->operand[16] = 0x00; /* network_ID[1] */
/* Add PIDs to filter */
- c->length = ALIGN(17 + add_pid_filter(fdtv, &c->operand[17]) + 3, 4);
+ fdtv->avc_data_length =
+ ALIGN(17 + add_pid_filter(fdtv, &c->operand[17]) + 3, 4);
}
int avc_tuner_dsd(struct firedtv *fdtv,
struct dvb_frontend_parameters *params)
{
- char buffer[sizeof(struct avc_command_frame)];
- struct avc_command_frame *c = (void *)buffer;
- struct avc_response_frame *r = (void *)buffer; /* FIXME: unused */
+ struct avc_command_frame *c = (void *)fdtv->avc_data;
+ int ret;
+
+ if (mutex_lock_interruptible(&fdtv->avc_mutex))
+ return -EINTR;
memset(c, 0, sizeof(*c));
@@ -561,36 +552,41 @@ int avc_tuner_dsd(struct firedtv *fdtv,
switch (fdtv->type) {
case FIREDTV_DVB_S:
- case FIREDTV_DVB_S2: avc_tuner_tuneqpsk(fdtv, params, c); break;
- case FIREDTV_DVB_C: avc_tuner_dsd_dvb_c(fdtv, params, c); break;
- case FIREDTV_DVB_T: avc_tuner_dsd_dvb_t(fdtv, params, c); break;
+ case FIREDTV_DVB_S2: avc_tuner_tuneqpsk(fdtv, params); break;
+ case FIREDTV_DVB_C: avc_tuner_dsd_dvb_c(fdtv, params); break;
+ case FIREDTV_DVB_T: avc_tuner_dsd_dvb_t(fdtv, params); break;
default:
BUG();
}
-
- if (avc_write(fdtv, c, r) < 0)
- return -EIO;
-
- msleep(500);
+ ret = avc_write(fdtv);
#if 0
- /* FIXME: */
- /* u8 *status was an out-parameter of avc_tuner_dsd, unused by caller */
+ /*
+ * FIXME:
+ * u8 *status was an out-parameter of avc_tuner_dsd, unused by caller.
+ * Check for AVC_RESPONSE_ACCEPTED here instead?
+ */
if (status)
*status = r->operand[2];
#endif
- return 0;
+ mutex_unlock(&fdtv->avc_mutex);
+
+ if (ret == 0)
+ msleep(500);
+
+ return ret;
}
int avc_tuner_set_pids(struct firedtv *fdtv, unsigned char pidc, u16 pid[])
{
- char buffer[sizeof(struct avc_command_frame)];
- struct avc_command_frame *c = (void *)buffer;
- struct avc_response_frame *r = (void *)buffer; /* FIXME: unused */
- int pos, k;
+ struct avc_command_frame *c = (void *)fdtv->avc_data;
+ int ret, pos, k;
if (pidc > 16 && pidc != 0xff)
return -EINVAL;
+ if (mutex_lock_interruptible(&fdtv->avc_mutex))
+ return -EINTR;
+
memset(c, 0, sizeof(*c));
c->ctype = AVC_CTYPE_CONTROL;
@@ -615,21 +611,26 @@ int avc_tuner_set_pids(struct firedtv *fdtv, unsigned char pidc, u16 pid[])
c->operand[pos++] = 0x00; /* filter_length */
}
- c->length = ALIGN(3 + pos, 4);
+ fdtv->avc_data_length = ALIGN(3 + pos, 4);
+ ret = avc_write(fdtv);
- if (avc_write(fdtv, c, r) < 0)
- return -EIO;
+ /* FIXME: check response code? */
- msleep(50);
- return 0;
+ mutex_unlock(&fdtv->avc_mutex);
+
+ if (ret == 0)
+ msleep(50);
+
+ return ret;
}
int avc_tuner_get_ts(struct firedtv *fdtv)
{
- char buffer[sizeof(struct avc_command_frame)];
- struct avc_command_frame *c = (void *)buffer;
- struct avc_response_frame *r = (void *)buffer; /* FIXME: unused */
- int sl;
+ struct avc_command_frame *c = (void *)fdtv->avc_data;
+ int ret, sl;
+
+ if (mutex_lock_interruptible(&fdtv->avc_mutex))
+ return -EINTR;
memset(c, 0, sizeof(*c));
@@ -650,20 +651,27 @@ int avc_tuner_get_ts(struct firedtv *fdtv)
c->operand[8] = 0x00; /* valid_flags [1] */
c->operand[7 + sl] = 0x00; /* nr_of_dsit_sel_specs (always 0) */
- c->length = fdtv->type == FIREDTV_DVB_T ? 24 : 28;
+ fdtv->avc_data_length = fdtv->type == FIREDTV_DVB_T ? 24 : 28;
+ ret = avc_write(fdtv);
- if (avc_write(fdtv, c, r) < 0)
- return -EIO;
+ /* FIXME: check response code? */
- msleep(250);
- return 0;
+ mutex_unlock(&fdtv->avc_mutex);
+
+ if (ret == 0)
+ msleep(250);
+
+ return ret;
}
int avc_identify_subunit(struct firedtv *fdtv)
{
- char buffer[sizeof(struct avc_command_frame)];
- struct avc_command_frame *c = (void *)buffer;
- struct avc_response_frame *r = (void *)buffer;
+ struct avc_command_frame *c = (void *)fdtv->avc_data;
+ struct avc_response_frame *r = (void *)fdtv->avc_data;
+ int ret;
+
+ if (mutex_lock_interruptible(&fdtv->avc_mutex))
+ return -EINTR;
memset(c, 0, sizeof(*c));
@@ -679,28 +687,33 @@ int avc_identify_subunit(struct firedtv *fdtv)
c->operand[5] = 0x00; /* offset highbyte */
c->operand[6] = 0x0d; /* offset lowbyte */
- c->length = 12;
-
- if (avc_write(fdtv, c, r) < 0)
- return -EIO;
+ fdtv->avc_data_length = 12;
+ ret = avc_write(fdtv);
+ if (ret < 0)
+ goto out;
if ((r->response != AVC_RESPONSE_STABLE &&
r->response != AVC_RESPONSE_ACCEPTED) ||
(r->operand[3] << 8) + r->operand[4] != 8) {
dev_err(fdtv->device, "cannot read subunit identifier\n");
- return -EINVAL;
+ ret = -EINVAL;
}
- return 0;
+out:
+ mutex_unlock(&fdtv->avc_mutex);
+
+ return ret;
}
#define SIZEOF_ANTENNA_INPUT_INFO 22
int avc_tuner_status(struct firedtv *fdtv, struct firedtv_tuner_status *stat)
{
- char buffer[sizeof(struct avc_command_frame)];
- struct avc_command_frame *c = (void *)buffer;
- struct avc_response_frame *r = (void *)buffer;
- int length;
+ struct avc_command_frame *c = (void *)fdtv->avc_data;
+ struct avc_response_frame *r = (void *)fdtv->avc_data;
+ int length, ret;
+
+ if (mutex_lock_interruptible(&fdtv->avc_mutex))
+ return -EINTR;
memset(c, 0, sizeof(*c));
@@ -716,21 +729,23 @@ int avc_tuner_status(struct firedtv *fdtv, struct firedtv_tuner_status *stat)
c->operand[5] = 0x00;
c->operand[6] = 0x00;
- c->length = 12;
-
- if (avc_write(fdtv, c, r) < 0)
- return -EIO;
+ fdtv->avc_data_length = 12;
+ ret = avc_write(fdtv);
+ if (ret < 0)
+ goto out;
if (r->response != AVC_RESPONSE_STABLE &&
r->response != AVC_RESPONSE_ACCEPTED) {
dev_err(fdtv->device, "cannot read tuner status\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
length = r->operand[9];
if (r->operand[1] != 0x10 || length != SIZEOF_ANTENNA_INPUT_INFO) {
dev_err(fdtv->device, "got invalid tuner status\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
stat->active_system = r->operand[10];
@@ -766,18 +781,22 @@ int avc_tuner_status(struct firedtv *fdtv, struct firedtv_tuner_status *stat)
stat->ca_dvb_flag = r->operand[31] >> 3 & 1;
stat->ca_error_flag = r->operand[31] >> 2 & 1;
stat->ca_initialization_status = r->operand[31] >> 1 & 1;
+out:
+ mutex_unlock(&fdtv->avc_mutex);
- return 0;
+ return ret;
}
int avc_lnb_control(struct firedtv *fdtv, char voltage, char burst,
char conttone, char nrdiseq,
struct dvb_diseqc_master_cmd *diseqcmd)
{
- char buffer[sizeof(struct avc_command_frame)];
- struct avc_command_frame *c = (void *)buffer;
- struct avc_response_frame *r = (void *)buffer;
- int i, j, k;
+ struct avc_command_frame *c = (void *)fdtv->avc_data;
+ struct avc_response_frame *r = (void *)fdtv->avc_data;
+ int i, j, k, ret;
+
+ if (mutex_lock_interruptible(&fdtv->avc_mutex))
+ return -EINTR;
memset(c, 0, sizeof(*c));
@@ -805,23 +824,28 @@ int avc_lnb_control(struct firedtv *fdtv, char voltage, char burst,
c->operand[i++] = burst;
c->operand[i++] = conttone;
- c->length = ALIGN(3 + i, 4);
-
- if (avc_write(fdtv, c, r) < 0)
- return -EIO;
+ fdtv->avc_data_length = ALIGN(3 + i, 4);
+ ret = avc_write(fdtv);
+ if (ret < 0)
+ goto out;
if (r->response != AVC_RESPONSE_ACCEPTED) {
dev_err(fdtv->device, "LNB control failed\n");
- return -EINVAL;
+ ret = -EINVAL;
}
+out:
+ mutex_unlock(&fdtv->avc_mutex);
- return 0;
+ return ret;
}
int avc_register_remote_control(struct firedtv *fdtv)
{
- char buffer[sizeof(struct avc_command_frame)];
- struct avc_command_frame *c = (void *)buffer;
+ struct avc_command_frame *c = (void *)fdtv->avc_data;
+ int ret;
+
+ if (mutex_lock_interruptible(&fdtv->avc_mutex))
+ return -EINTR;
memset(c, 0, sizeof(*c));
@@ -834,9 +858,14 @@ int avc_register_remote_control(struct firedtv *fdtv)
c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
c->operand[3] = SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL;
- c->length = 8;
+ fdtv->avc_data_length = 8;
+ ret = avc_write(fdtv);
- return avc_write(fdtv, c, NULL);
+ /* FIXME: check response code? */
+
+ mutex_unlock(&fdtv->avc_mutex);
+
+ return ret;
}
void avc_remote_ctrl_work(struct work_struct *work)
@@ -851,9 +880,11 @@ void avc_remote_ctrl_work(struct work_struct *work)
#if 0 /* FIXME: unused */
int avc_tuner_host2ca(struct firedtv *fdtv)
{
- char buffer[sizeof(struct avc_command_frame)];
- struct avc_command_frame *c = (void *)buffer;
- struct avc_response_frame *r = (void *)buffer; /* FIXME: unused */
+ struct avc_command_frame *c = (void *)fdtv->avc_data;
+ int ret;
+
+ if (mutex_lock_interruptible(&fdtv->avc_mutex))
+ return -EINTR;
memset(c, 0, sizeof(*c));
@@ -870,12 +901,14 @@ int avc_tuner_host2ca(struct firedtv *fdtv)
c->operand[6] = 0; /* more/last */
c->operand[7] = 0; /* length */
- c->length = 12;
+ fdtv->avc_data_length = 12;
+ ret = avc_write(fdtv);
- if (avc_write(fdtv, c, r) < 0)
- return -EIO;
+ /* FIXME: check response code? */
- return 0;
+ mutex_unlock(&fdtv->avc_mutex);
+
+ return ret;
}
#endif
@@ -906,10 +939,12 @@ static int get_ca_object_length(struct avc_response_frame *r)
int avc_ca_app_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
{
- char buffer[sizeof(struct avc_command_frame)];
- struct avc_command_frame *c = (void *)buffer;
- struct avc_response_frame *r = (void *)buffer;
- int pos;
+ struct avc_command_frame *c = (void *)fdtv->avc_data;
+ struct avc_response_frame *r = (void *)fdtv->avc_data;
+ int pos, ret;
+
+ if (mutex_lock_interruptible(&fdtv->avc_mutex))
+ return -EINTR;
memset(c, 0, sizeof(*c));
@@ -924,10 +959,10 @@ int avc_ca_app_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
c->operand[4] = 0; /* slot */
c->operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; /* ca tag */
- c->length = 12;
-
- if (avc_write(fdtv, c, r) < 0)
- return -EIO;
+ fdtv->avc_data_length = 12;
+ ret = avc_write(fdtv);
+ if (ret < 0)
+ goto out;
/* FIXME: check response code and validate response data */
@@ -939,16 +974,20 @@ int avc_ca_app_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
app_info[4] = 0x01;
memcpy(&app_info[5], &r->operand[pos], 5 + r->operand[pos + 4]);
*len = app_info[3] + 4;
+out:
+ mutex_unlock(&fdtv->avc_mutex);
- return 0;
+ return ret;
}
int avc_ca_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
{
- char buffer[sizeof(struct avc_command_frame)];
- struct avc_command_frame *c = (void *)buffer;
- struct avc_response_frame *r = (void *)buffer;
- int pos;
+ struct avc_command_frame *c = (void *)fdtv->avc_data;
+ struct avc_response_frame *r = (void *)fdtv->avc_data;
+ int pos, ret;
+
+ if (mutex_lock_interruptible(&fdtv->avc_mutex))
+ return -EINTR;
memset(c, 0, sizeof(*c));
@@ -963,10 +1002,12 @@ int avc_ca_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
c->operand[4] = 0; /* slot */
c->operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; /* ca tag */
- c->length = 12;
+ fdtv->avc_data_length = 12;
+ ret = avc_write(fdtv);
+ if (ret < 0)
+ goto out;
- if (avc_write(fdtv, c, r) < 0)
- return -EIO;
+ /* FIXME: check response code and validate response data */
pos = get_ca_object_pos(r);
app_info[0] = (EN50221_TAG_CA_INFO >> 16) & 0xff;
@@ -976,15 +1017,19 @@ int avc_ca_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
app_info[4] = r->operand[pos + 0];
app_info[5] = r->operand[pos + 1];
*len = app_info[3] + 4;
+out:
+ mutex_unlock(&fdtv->avc_mutex);
- return 0;
+ return ret;
}
int avc_ca_reset(struct firedtv *fdtv)
{
- char buffer[sizeof(struct avc_command_frame)];
- struct avc_command_frame *c = (void *)buffer;
- struct avc_response_frame *r = (void *)buffer; /* FIXME: unused */
+ struct avc_command_frame *c = (void *)fdtv->avc_data;
+ int ret;
+
+ if (mutex_lock_interruptible(&fdtv->avc_mutex))
+ return -EINTR;
memset(c, 0, sizeof(*c));
@@ -1002,19 +1047,20 @@ int avc_ca_reset(struct firedtv *fdtv)
c->operand[7] = 1; /* length */
c->operand[8] = 0; /* force hardware reset */
- c->length = 12;
+ fdtv->avc_data_length = 12;
+ ret = avc_write(fdtv);
- if (avc_write(fdtv, c, r) < 0)
- return -EIO;
+ /* FIXME: check response code? */
- return 0;
+ mutex_unlock(&fdtv->avc_mutex);
+
+ return ret;
}
int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length)
{
- char buffer[sizeof(struct avc_command_frame)];
- struct avc_command_frame *c = (void *)buffer;
- struct avc_response_frame *r = (void *)buffer;
+ struct avc_command_frame *c = (void *)fdtv->avc_data;
+ struct avc_response_frame *r = (void *)fdtv->avc_data;
int list_management;
int program_info_length;
int pmt_cmd_id;
@@ -1022,10 +1068,14 @@ int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length)
int write_pos;
int es_info_length;
int crc32_csum;
+ int ret;
if (unlikely(avc_debug & AVC_DEBUG_APPLICATION_PMT))
debug_pmt(msg, length);
+ if (mutex_lock_interruptible(&fdtv->avc_mutex))
+ return -EINTR;
+
memset(c, 0, sizeof(*c));
c->ctype = AVC_CTYPE_CONTROL;
@@ -1124,25 +1174,30 @@ int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length)
c->operand[write_pos - 2] = (crc32_csum >> 8) & 0xff;
c->operand[write_pos - 1] = (crc32_csum >> 0) & 0xff;
- c->length = ALIGN(3 + write_pos, 4);
-
- if (avc_write(fdtv, c, r) < 0)
- return -EIO;
+ fdtv->avc_data_length = ALIGN(3 + write_pos, 4);
+ ret = avc_write(fdtv);
+ if (ret < 0)
+ goto out;
if (r->response != AVC_RESPONSE_ACCEPTED) {
dev_err(fdtv->device,
"CA PMT failed with response 0x%x\n", r->response);
- return -EFAULT;
+ ret = -EFAULT;
}
+out:
+ mutex_unlock(&fdtv->avc_mutex);
- return 0;
+ return ret;
}
int avc_ca_get_time_date(struct firedtv *fdtv, int *interval)
{
- char buffer[sizeof(struct avc_command_frame)];
- struct avc_command_frame *c = (void *)buffer;
- struct avc_response_frame *r = (void *)buffer;
+ struct avc_command_frame *c = (void *)fdtv->avc_data;
+ struct avc_response_frame *r = (void *)fdtv->avc_data;
+ int ret;
+
+ if (mutex_lock_interruptible(&fdtv->avc_mutex))
+ return -EINTR;
memset(c, 0, sizeof(*c));
@@ -1159,23 +1214,27 @@ int avc_ca_get_time_date(struct firedtv *fdtv, int *interval)
c->operand[6] = 0; /* more/last */
c->operand[7] = 0; /* length */
- c->length = 12;
-
- if (avc_write(fdtv, c, r) < 0)
- return -EIO;
+ fdtv->avc_data_length = 12;
+ ret = avc_write(fdtv);
+ if (ret < 0)
+ goto out;
/* FIXME: check response code and validate response data */
*interval = r->operand[get_ca_object_pos(r)];
+out:
+ mutex_unlock(&fdtv->avc_mutex);
- return 0;
+ return ret;
}
int avc_ca_enter_menu(struct firedtv *fdtv)
{
- char buffer[sizeof(struct avc_command_frame)];
- struct avc_command_frame *c = (void *)buffer;
- struct avc_response_frame *r = (void *)buffer; /* FIXME: unused */
+ struct avc_command_frame *c = (void *)fdtv->avc_data;
+ int ret;
+
+ if (mutex_lock_interruptible(&fdtv->avc_mutex))
+ return -EINTR;
memset(c, 0, sizeof(*c));
@@ -1192,19 +1251,24 @@ int avc_ca_enter_menu(struct firedtv *fdtv)
c->operand[6] = 0; /* more/last */
c->operand[7] = 0; /* length */
- c->length = 12;
+ fdtv->avc_data_length = 12;
+ ret = avc_write(fdtv);
- if (avc_write(fdtv, c, r) < 0)
- return -EIO;
+ /* FIXME: check response code? */
- return 0;
+ mutex_unlock(&fdtv->avc_mutex);
+
+ return ret;
}
int avc_ca_get_mmi(struct firedtv *fdtv, char *mmi_object, unsigned int *len)
{
- char buffer[sizeof(struct avc_command_frame)];
- struct avc_command_frame *c = (void *)buffer;
- struct avc_response_frame *r = (void *)buffer;
+ struct avc_command_frame *c = (void *)fdtv->avc_data;
+ struct avc_response_frame *r = (void *)fdtv->avc_data;
+ int ret;
+
+ if (mutex_lock_interruptible(&fdtv->avc_mutex))
+ return -EINTR;
memset(c, 0, sizeof(*c));
@@ -1221,17 +1285,19 @@ int avc_ca_get_mmi(struct firedtv *fdtv, char *mmi_object, unsigned int *len)
c->operand[6] = 0; /* more/last */
c->operand[7] = 0; /* length */
- c->length = 12;
-
- if (avc_write(fdtv, c, r) < 0)
- return -EIO;
+ fdtv->avc_data_length = 12;
+ ret = avc_write(fdtv);
+ if (ret < 0)
+ goto out;
/* FIXME: check response code and validate response data */
*len = get_ca_object_length(r);
memcpy(mmi_object, &r->operand[get_ca_object_pos(r)], *len);
+out:
+ mutex_unlock(&fdtv->avc_mutex);
- return 0;
+ return ret;
}
#define CMP_OUTPUT_PLUG_CONTROL_REG_0 0xfffff0000904ULL
@@ -1248,6 +1314,7 @@ static int cmp_read(struct firedtv *fdtv, u64 addr, __be32 *data)
dev_err(fdtv->device, "CMP: read I/O error\n");
mutex_unlock(&fdtv->avc_mutex);
+
return ret;
}
@@ -1258,11 +1325,17 @@ static int cmp_lock(struct firedtv *fdtv, u64 addr, __be32 data[])
if (mutex_lock_interruptible(&fdtv->avc_mutex))
return -EINTR;
- ret = fdtv->backend->lock(fdtv, addr, data);
+ /* data[] is stack-allocated and should not be DMA-mapped. */
+ memcpy(fdtv->avc_data, data, 8);
+
+ ret = fdtv->backend->lock(fdtv, addr, fdtv->avc_data);
if (ret < 0)
dev_err(fdtv->device, "CMP: lock I/O error\n");
+ else
+ memcpy(data, fdtv->avc_data, 8);
mutex_unlock(&fdtv->avc_mutex);
+
return ret;
}