diff options
author | NooneImportant <nxhxzi702@sneakemail.com> | 2005-11-09 00:35:27 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-11-09 10:56:03 -0500 |
commit | 83b75b049be981e579ba2cb88aa9bf3534bbbdb1 (patch) | |
tree | c7d6199e9c6b5373b373439148da7dc4f48a0698 /drivers/media | |
parent | b90ed914e513a6ad6184f7a46a0df0888dcfc177 (diff) |
[PATCH] dvb: let other frontends support FE_DISHNETWORK_SEND_LEGACY_CMD
Add support to FE_DISHNETWORK_SEND_LEGACY_CMD code to support other frontends
besides stv0299. The generic code is a fallback in the case that it doesn't
work for some specific frontends (again stv0299 being a good example).
Signed-off-by: NooneImportant <nxhxzi702@sneakemail.com>
Signed-off-by: Johannes Stezenbach <js@linuxtv.org>
Signed-off-by: Michael Krufky <mkrufky@linuxtv.org>
Cc: Johannes Stezenbach <js@linuxtv.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/media')
-rw-r--r-- | drivers/media/dvb/dvb-core/dvb_frontend.c | 97 | ||||
-rw-r--r-- | drivers/media/dvb/dvb-core/dvb_frontend.h | 3 | ||||
-rw-r--r-- | drivers/media/dvb/frontends/stv0299.c | 38 |
3 files changed, 104 insertions, 34 deletions
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index a8bc84240b50..e36dbd9c4cc5 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c | |||
@@ -577,6 +577,49 @@ static void dvb_frontend_stop(struct dvb_frontend *fe) | |||
577 | fepriv->thread_pid); | 577 | fepriv->thread_pid); |
578 | } | 578 | } |
579 | 579 | ||
580 | s32 timeval_usec_diff(struct timeval lasttime, struct timeval curtime) | ||
581 | { | ||
582 | return ((curtime.tv_usec < lasttime.tv_usec) ? | ||
583 | 1000000 - lasttime.tv_usec + curtime.tv_usec : | ||
584 | curtime.tv_usec - lasttime.tv_usec); | ||
585 | } | ||
586 | EXPORT_SYMBOL(timeval_usec_diff); | ||
587 | |||
588 | static inline void timeval_usec_add(struct timeval *curtime, u32 add_usec) | ||
589 | { | ||
590 | curtime->tv_usec += add_usec; | ||
591 | if (curtime->tv_usec >= 1000000) { | ||
592 | curtime->tv_usec -= 1000000; | ||
593 | curtime->tv_sec++; | ||
594 | } | ||
595 | } | ||
596 | |||
597 | /* | ||
598 | * Sleep until gettimeofday() > waketime + add_usec | ||
599 | * This needs to be as precise as possible, but as the delay is | ||
600 | * usually between 2ms and 32ms, it is done using a scheduled msleep | ||
601 | * followed by usleep (normally a busy-wait loop) for the remainder | ||
602 | */ | ||
603 | void dvb_frontend_sleep_until(struct timeval *waketime, u32 add_usec) | ||
604 | { | ||
605 | struct timeval lasttime; | ||
606 | s32 delta, newdelta; | ||
607 | |||
608 | timeval_usec_add(waketime, add_usec); | ||
609 | |||
610 | do_gettimeofday(&lasttime); | ||
611 | delta = timeval_usec_diff(lasttime, *waketime); | ||
612 | if (delta > 2500) { | ||
613 | msleep((delta - 1500) / 1000); | ||
614 | do_gettimeofday(&lasttime); | ||
615 | newdelta = timeval_usec_diff(lasttime, *waketime); | ||
616 | delta = (newdelta > delta) ? 0 : newdelta; | ||
617 | } | ||
618 | if (delta > 0) | ||
619 | udelay(delta); | ||
620 | } | ||
621 | EXPORT_SYMBOL(dvb_frontend_sleep_until); | ||
622 | |||
580 | static int dvb_frontend_start(struct dvb_frontend *fe) | 623 | static int dvb_frontend_start(struct dvb_frontend *fe) |
581 | { | 624 | { |
582 | int ret; | 625 | int ret; |
@@ -728,6 +771,60 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, | |||
728 | err = fe->ops->dishnetwork_send_legacy_command(fe, (unsigned int) parg); | 771 | err = fe->ops->dishnetwork_send_legacy_command(fe, (unsigned int) parg); |
729 | fepriv->state = FESTATE_DISEQC; | 772 | fepriv->state = FESTATE_DISEQC; |
730 | fepriv->status = 0; | 773 | fepriv->status = 0; |
774 | } else if (fe->ops->set_voltage) { | ||
775 | /* | ||
776 | * NOTE: This is a fallback condition. Some frontends | ||
777 | * (stv0299 for instance) take longer than 8msec to | ||
778 | * respond to a set_voltage command. Those switches | ||
779 | * need custom routines to switch properly. For all | ||
780 | * other frontends, the following shoule work ok. | ||
781 | * Dish network legacy switches (as used by Dish500) | ||
782 | * are controlled by sending 9-bit command words | ||
783 | * spaced 8msec apart. | ||
784 | * the actual command word is switch/port dependant | ||
785 | * so it is up to the userspace application to send | ||
786 | * the right command. | ||
787 | * The command must always start with a '0' after | ||
788 | * initialization, so parg is 8 bits and does not | ||
789 | * include the initialization or start bit | ||
790 | */ | ||
791 | unsigned int cmd = ((unsigned int) parg) << 1; | ||
792 | struct timeval nexttime; | ||
793 | struct timeval tv[10]; | ||
794 | int i; | ||
795 | u8 last = 1; | ||
796 | if (dvb_frontend_debug) | ||
797 | printk("%s switch command: 0x%04x\n", __FUNCTION__, cmd); | ||
798 | do_gettimeofday(&nexttime); | ||
799 | if (dvb_frontend_debug) | ||
800 | memcpy(&tv[0], &nexttime, sizeof(struct timeval)); | ||
801 | /* before sending a command, initialize by sending | ||
802 | * a 32ms 18V to the switch | ||
803 | */ | ||
804 | fe->ops->set_voltage(fe, SEC_VOLTAGE_18); | ||
805 | dvb_frontend_sleep_until(&nexttime, 32000); | ||
806 | |||
807 | for (i = 0; i < 9; i++) { | ||
808 | if (dvb_frontend_debug) | ||
809 | do_gettimeofday(&tv[i + 1]); | ||
810 | if ((cmd & 0x01) != last) { | ||
811 | /* set voltage to (last ? 13V : 18V) */ | ||
812 | fe->ops->set_voltage(fe, (last) ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18); | ||
813 | last = (last) ? 0 : 1; | ||
814 | } | ||
815 | cmd = cmd >> 1; | ||
816 | if (i != 8) | ||
817 | dvb_frontend_sleep_until(&nexttime, 8000); | ||
818 | } | ||
819 | if (dvb_frontend_debug) { | ||
820 | printk("%s(%d): switch delay (should be 32k followed by all 8k\n", | ||
821 | __FUNCTION__, fe->dvb->num); | ||
822 | for (i = 1; i < 10; i++) | ||
823 | printk("%d: %d\n", i, timeval_usec_diff(tv[i-1] , tv[i])); | ||
824 | } | ||
825 | err = 0; | ||
826 | fepriv->state = FESTATE_DISEQC; | ||
827 | fepriv->status = 0; | ||
731 | } | 828 | } |
732 | break; | 829 | break; |
733 | 830 | ||
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h index 9c2c1d1136bd..348c9b0b988a 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb/dvb-core/dvb_frontend.h | |||
@@ -101,4 +101,7 @@ extern int dvb_register_frontend(struct dvb_adapter* dvb, | |||
101 | 101 | ||
102 | extern int dvb_unregister_frontend(struct dvb_frontend* fe); | 102 | extern int dvb_unregister_frontend(struct dvb_frontend* fe); |
103 | 103 | ||
104 | extern void dvb_frontend_sleep_until(struct timeval *waketime, u32 add_usec); | ||
105 | extern s32 timeval_usec_diff(struct timeval lasttime, struct timeval curtime); | ||
106 | |||
104 | #endif | 107 | #endif |
diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c index b1876618a37d..ae00d7a40d7c 100644 --- a/drivers/media/dvb/frontends/stv0299.c +++ b/drivers/media/dvb/frontends/stv0299.c | |||
@@ -387,36 +387,6 @@ static int stv0299_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltag | |||
387 | }; | 387 | }; |
388 | } | 388 | } |
389 | 389 | ||
390 | static inline s32 stv0299_calc_usec_delay (struct timeval lasttime, struct timeval curtime) | ||
391 | { | ||
392 | return ((curtime.tv_usec < lasttime.tv_usec) ? | ||
393 | 1000000 - lasttime.tv_usec + curtime.tv_usec : | ||
394 | curtime.tv_usec - lasttime.tv_usec); | ||
395 | } | ||
396 | |||
397 | static void stv0299_sleep_until (struct timeval *waketime, u32 add_usec) | ||
398 | { | ||
399 | struct timeval lasttime; | ||
400 | s32 delta, newdelta; | ||
401 | |||
402 | waketime->tv_usec += add_usec; | ||
403 | if (waketime->tv_usec >= 1000000) { | ||
404 | waketime->tv_usec -= 1000000; | ||
405 | waketime->tv_sec++; | ||
406 | } | ||
407 | |||
408 | do_gettimeofday (&lasttime); | ||
409 | delta = stv0299_calc_usec_delay (lasttime, *waketime); | ||
410 | if (delta > 2500) { | ||
411 | msleep ((delta - 1500) / 1000); | ||
412 | do_gettimeofday (&lasttime); | ||
413 | newdelta = stv0299_calc_usec_delay (lasttime, *waketime); | ||
414 | delta = (newdelta > delta) ? 0 : newdelta; | ||
415 | } | ||
416 | if (delta > 0) | ||
417 | udelay (delta); | ||
418 | } | ||
419 | |||
420 | static int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, u32 cmd) | 390 | static int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, u32 cmd) |
421 | { | 391 | { |
422 | struct stv0299_state* state = fe->demodulator_priv; | 392 | struct stv0299_state* state = fe->demodulator_priv; |
@@ -444,7 +414,7 @@ static int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, u32 cmd) | |||
444 | memcpy (&tv[0], &nexttime, sizeof (struct timeval)); | 414 | memcpy (&tv[0], &nexttime, sizeof (struct timeval)); |
445 | stv0299_writeregI (state, 0x0c, reg0x0c | 0x50); /* set LNB to 18V */ | 415 | stv0299_writeregI (state, 0x0c, reg0x0c | 0x50); /* set LNB to 18V */ |
446 | 416 | ||
447 | stv0299_sleep_until (&nexttime, 32000); | 417 | dvb_frontend_sleep_until(&nexttime, 32000); |
448 | 418 | ||
449 | for (i=0; i<9; i++) { | 419 | for (i=0; i<9; i++) { |
450 | if (debug_legacy_dish_switch) | 420 | if (debug_legacy_dish_switch) |
@@ -458,13 +428,13 @@ static int stv0299_send_legacy_dish_cmd (struct dvb_frontend* fe, u32 cmd) | |||
458 | cmd = cmd >> 1; | 428 | cmd = cmd >> 1; |
459 | 429 | ||
460 | if (i != 8) | 430 | if (i != 8) |
461 | stv0299_sleep_until (&nexttime, 8000); | 431 | dvb_frontend_sleep_until(&nexttime, 8000); |
462 | } | 432 | } |
463 | if (debug_legacy_dish_switch) { | 433 | if (debug_legacy_dish_switch) { |
464 | printk ("%s(%d): switch delay (should be 32k followed by all 8k\n", | 434 | printk ("%s(%d): switch delay (should be 32k followed by all 8k\n", |
465 | __FUNCTION__, fe->dvb->num); | 435 | __FUNCTION__, fe->dvb->num); |
466 | for (i=1; i < 10; i++) | 436 | for (i = 1; i < 10; i++) |
467 | printk ("%d: %d\n", i, stv0299_calc_usec_delay (tv[i-1] , tv[i])); | 437 | printk ("%d: %d\n", i, timeval_usec_diff(tv[i-1] , tv[i])); |
468 | } | 438 | } |
469 | 439 | ||
470 | return 0; | 440 | return 0; |