diff options
-rw-r--r-- | linux/drivers/media/dvb/frontends/s5h1420.c | 93 |
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; } |