--- linux-2.6.11.6-orig/drivers/media/dvb/frontends/stv0299.c 2004-12-24 13:35:49.000000000 -0800 +++ linux-2.6.11.6/drivers/media/dvb/frontends/stv0299.c 2005-03-27 10:07:35.000000000 -0800 @@ -74,6 +74,7 @@ #define STATUS_UCBLOCKS 1 static int debug; +static int debug_dn_switch; #define dprintk(args...) \ do { \ if (debug) printk(KERN_DEBUG "stv0299: " args); \ @@ -412,37 +413,84 @@ }; } - +#define USEC_DELAY(b,a) (((a).tv_usec < (b).tv_usec) ? \ + 1000000 - (b).tv_usec + (a).tv_usec : (a).tv_usec - (b).tv_usec) +#define ADD_TIME_USECS(a,b) ({(a).tv_usec += (b); \ + if((a).tv_usec>=1000000) {(a).tv_usec-=1000000; (a).tv_sec++;}}) + +static void stv0299_sleep_until(struct timeval waketime) +{ + struct timeval lasttime; + s32 delta, newdelta; + do_gettimeofday(&lasttime); + delta=USEC_DELAY(lasttime,waketime); + if(delta > 2500) { + msleep((delta-1500)/1000); + do_gettimeofday(&lasttime); + newdelta=USEC_DELAY(lasttime,waketime); + delta=(newdelta>delta)? 0 : newdelta; + } + if(delta > 0) + udelay(delta); +} + static int stv0299_send_legacy_dish_cmd(struct dvb_frontend* fe, u32 cmd) { + struct stv0299_state* state = (struct stv0299_state*) fe->demodulator_priv; + u8 reg0x08; + u8 reg0x0c; + u8 lv_mask = 0x40; u8 last = 1; int i; - + struct timeval nexttime; + struct timeval tv[10]; /* reset voltage at the end if((0x50 & stv0299_readreg (i2c, 0x0c)) == 0x50) cmd |= 0x80; else cmd &= 0x7F; */ + reg0x08 = stv0299_readreg (state, 0x08); + reg0x0c = stv0299_readreg (state, 0x0c); + reg0x0c &= 0x0f; + stv0299_writeregI (state, 0x08, (reg0x08 & 0x3f) | (state->config->lock_output << 6)); + if (state->config->volt13_op0_op1 == STV0299_VOLT13_OP0) + lv_mask = 0x10; cmd = cmd << 1; - dprintk("%s switch command: 0x%04x\n",__FUNCTION__, cmd); + if(debug_dn_switch) + printk("%s switch command: 0x%04x\n",__FUNCTION__, cmd); + + do_gettimeofday(&nexttime); + if(debug_dn_switch) + memcpy(&tv[0], &nexttime, sizeof(struct timeval)); + stv0299_writeregI (state, 0x0c, reg0x0c | 0x50); /* set LNB to 18V */ - stv0299_set_voltage(fe,SEC_VOLTAGE_18); - msleep(32); + ADD_TIME_USECS(nexttime,32000); + stv0299_sleep_until(nexttime); for (i=0; i<9; i++) { + if(debug_dn_switch) + do_gettimeofday(&tv[i+1]); if((cmd & 0x01) != last) { - stv0299_set_voltage(fe, - last ? SEC_VOLTAGE_13 : - SEC_VOLTAGE_18); + /* set voltage to (last ? 13V : 18V) */ + stv0299_writeregI (state, 0x0c, reg0x0c | + (last ? lv_mask : 0x50)); last = (last) ? 0 : 1; } cmd = cmd >> 1; - if (i != 8) - msleep(8); + if (i != 8) { + ADD_TIME_USECS(nexttime,8000); + stv0299_sleep_until(nexttime); + } + } + if(debug_dn_switch) { + printk("%s(%d): switch delay (should be 32k followed by all 8k\n", + __FUNCTION__, fe->dvb->num); + for(i=1; i < 10; i++) + printk("%d: %lu\n",i, USEC_DELAY(tv[i-1] , tv[i])); } return 0; @@ -751,6 +799,9 @@ .dishnetwork_send_legacy_command = stv0299_send_legacy_dish_cmd, }; +module_param(debug_dn_switch, int, 0444); +MODULE_PARM_DESC(debug_dn_switch, "Enable timing analysis for Dish Network legacy switches"); + module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");