summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--linux/drivers/media/dvb/frontends/s5h1420.c93
1 files changed, 84 insertions, 9 deletions
diff --git a/linux/drivers/media/dvb/frontends/s5h1420.c b/linux/drivers/media/dvb/frontends/s5h1420.c
index 2d95c9d2a..8d3b42d7d 100644
--- a/linux/drivers/media/dvb/frontends/s5h1420.c
+++ b/linux/drivers/media/dvb/frontends/s5h1420.c
@@ -75,7 +75,7 @@ static u8 s5h1420_readreg (struct s5h1420_state* state, u8 reg)
if ((ret = i2c_transfer (state->i2c, &msg2, 1)) != 1)
return ret;
-
+
return b1[0];
}
@@ -120,17 +120,93 @@ static int s5h1420_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
static int s5h1420_send_master_cmd (struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
{
struct s5h1420_state* state = fe->demodulator_priv;
+ u8 val;
+ int i;
+ unsigned long timeout;
+ int result = 0;
- // FIXME
- return 0;
+ /* setup for DISEQC */
+ val = s5h1420_readreg(state, 0x3b);
+ s5h1420_writereg(state, 0x3b, 0x02);
+ msleep(15);
+
+ /* write the DISEQC command bytes */
+ for(i=0; i< cmd->msg_len; i++) {
+ s5h1420_writereg(state, 0x3c + i, cmd->msg[i]);
+ }
+
+ /* kick off transmission */
+ s5h1420_writereg(state, 0x3b, s5h1420_readreg(state, 0x3b) | ((cmd->msg_len-1) << 4) | 0x08);
+
+ /* wait for transmission to complete */
+ timeout = jiffies + ((100*HZ) / 1000);
+ while(time_before(jiffies, timeout)) {
+ if (s5h1420_readreg(state, 0x3b) & 0x08)
+ break;
+
+ msleep(5);
+ }
+ if (time_after(jiffies, timeout))
+ result = -ETIMEDOUT;
+
+ /* restore original settings */
+ s5h1420_writereg(state, 0x3b, val);
+ msleep(15);
+ return result;
}
static int s5h1420_recv_slave_reply (struct dvb_frontend* fe, struct dvb_diseqc_slave_reply* reply)
{
struct s5h1420_state* state = fe->demodulator_priv;
+ u8 val;
+ int i;
+ int length;
+ unsigned long timeout;
+ int result = 0;
- // FIXME
- return 0;
+ /* setup for DISEQC recieve */
+ val = s5h1420_readreg(state, 0x3b);
+ s5h1420_writereg(state, 0x3b, 0x82); /* FIXME: guess - do we need to set DIS_RDY(0x08) in receive mode? */
+ msleep(15);
+
+ /* wait for reception to complete */
+ timeout = jiffies + ((reply->timeout*HZ) / 1000);
+ while(time_before(jiffies, timeout)) {
+ if (!(s5h1420_readreg(state, 0x3b) & 0x80)) /* FIXME: do we test DIS_RDY(0x08) or RCV_EN(0x80)? */
+ break;
+
+ msleep(5);
+ }
+ if (time_after(jiffies, timeout)) {
+ result = -ETIMEDOUT;
+ goto exit;
+ }
+
+ /* check error flag - FIXME: not sure what this does - docs do not describe
+ * beyond "error flag for diseqc receive data :( */
+ if (s5h1420_readreg(state, 0x49)) {
+ result = -EIO;
+ goto exit;
+ }
+
+ /* check length */
+ length = (s5h1420_readreg(state, 0x3b) & 0x70) >> 4;
+ if (length > sizeof(reply->msg)) {
+ result = -EOVERFLOW;
+ goto exit;
+ }
+ reply->msg_len = length;
+
+ /* extract data */
+ for(i=0; i< length; i++) {
+ reply->msg[i] = s5h1420_readreg(state, 0x3c + i);
+ }
+
+exit:
+ /* restore original settings */
+ s5h1420_writereg(state, 0x3b, val);
+ msleep(15);
+ return result;
}
static int s5h1420_send_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
@@ -156,18 +232,17 @@ static int s5h1420_send_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t minicm
/* wait for transmission to complete */
timeout = jiffies + ((20*HZ) / 1000);
while(time_before(jiffies, timeout)) {
- if (s5h1420_readreg(state, 0x3b) & 0x08)
+ if (!(s5h1420_readreg(state, 0x3b) & 0x08))
break;
- msleep(1);
+ msleep(5);
}
if (time_after(jiffies, timeout))
result = -ETIMEDOUT;
/* restore original settings */
- msleep(15);
s5h1420_writereg(state, 0x3b, val);
-
+ msleep(15);
return result;
}