aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew de Quincey <adq_dvb@lidskialf.net>2006-01-09 12:25:07 -0500
committerMauro Carvalho Chehab <mchehab@brturbo.com.br>2006-01-09 12:25:07 -0500
commit36cb557a2f64513e2fdc1a542167e5e8a6c1c67e (patch)
tree02822705dd0bafb191f4fe26fb3f28ef876b1429
parent47f3692096eef208d8cb455bfa2b3308cdfc40de (diff)
DVB (2444): Implement frontend-specific tuning and the ability to disable zigzag
- Implement frontend-specific tuning and the ability to disable zigzag Signed-off-by: Andrew de Quincey <adq_dvb@lidskialf.net> Signed-off-by: Mauro Carvalho Chehab <mchehab@brturbo.com.br>
-rw-r--r--drivers/media/dvb/bt8xx/dst.c52
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.c307
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.h11
-rw-r--r--include/linux/dvb/frontend.h10
4 files changed, 228 insertions, 152 deletions
diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c
index 8977c7a313df..3a2ff1cc24b7 100644
--- a/drivers/media/dvb/bt8xx/dst.c
+++ b/drivers/media/dvb/bt8xx/dst.c
@@ -1341,30 +1341,40 @@ static int dst_read_snr(struct dvb_frontend *fe, u16 *snr)
1341 return 0; 1341 return 0;
1342} 1342}
1343 1343
1344static int dst_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) 1344static int dst_set_frontend(struct dvb_frontend* fe,
1345 struct dvb_frontend_parameters* p,
1346 unsigned int mode_flags,
1347 int *delay,
1348 fe_status_t *status)
1345{ 1349{
1346 struct dst_state *state = fe->demodulator_priv; 1350 struct dst_state *state = fe->demodulator_priv;
1347 1351
1348 dst_set_freq(state, p->frequency); 1352 if (p != NULL) {
1349 dprintk(verbose, DST_DEBUG, 1, "Set Frequency=[%d]", p->frequency); 1353 dst_set_freq(state, p->frequency);
1354 dprintk(verbose, DST_DEBUG, 1, "Set Frequency=[%d]", p->frequency);
1350 1355
1351 if (state->dst_type == DST_TYPE_IS_SAT) { 1356 if (state->dst_type == DST_TYPE_IS_SAT) {
1352 if (state->type_flags & DST_TYPE_HAS_OBS_REGS) 1357 if (state->type_flags & DST_TYPE_HAS_OBS_REGS)
1353 dst_set_inversion(state, p->inversion); 1358 dst_set_inversion(state, p->inversion);
1354 dst_set_fec(state, p->u.qpsk.fec_inner); 1359 dst_set_fec(state, p->u.qpsk.fec_inner);
1355 dst_set_symbolrate(state, p->u.qpsk.symbol_rate); 1360 dst_set_symbolrate(state, p->u.qpsk.symbol_rate);
1356 dst_set_polarization(state); 1361 dst_set_polarization(state);
1357 dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", p->u.qpsk.symbol_rate); 1362 dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", p->u.qpsk.symbol_rate);
1358 1363
1359 } else if (state->dst_type == DST_TYPE_IS_TERR) 1364 } else if (state->dst_type == DST_TYPE_IS_TERR)
1360 dst_set_bandwidth(state, p->u.ofdm.bandwidth); 1365 dst_set_bandwidth(state, p->u.ofdm.bandwidth);
1361 else if (state->dst_type == DST_TYPE_IS_CABLE) { 1366 else if (state->dst_type == DST_TYPE_IS_CABLE) {
1362 dst_set_fec(state, p->u.qam.fec_inner); 1367 dst_set_fec(state, p->u.qam.fec_inner);
1363 dst_set_symbolrate(state, p->u.qam.symbol_rate); 1368 dst_set_symbolrate(state, p->u.qam.symbol_rate);
1364 dst_set_modulation(state, p->u.qam.modulation); 1369 dst_set_modulation(state, p->u.qam.modulation);
1370 }
1371 dst_write_tuna(fe);
1365 } 1372 }
1366 dst_write_tuna(fe);
1367 1373
1374 if (!(mode_flags & FE_TUNE_MODE_ONESHOT))
1375 dst_read_status(fe, status);
1376
1377 *delay = HZ/10;
1368 return 0; 1378 return 0;
1369} 1379}
1370 1380
@@ -1445,7 +1455,7 @@ static struct dvb_frontend_ops dst_dvbt_ops = {
1445 1455
1446 .release = dst_release, 1456 .release = dst_release,
1447 .init = dst_init, 1457 .init = dst_init,
1448 .set_frontend = dst_set_frontend, 1458 .tune = dst_set_frontend,
1449 .get_frontend = dst_get_frontend, 1459 .get_frontend = dst_get_frontend,
1450 .read_status = dst_read_status, 1460 .read_status = dst_read_status,
1451 .read_signal_strength = dst_read_signal_strength, 1461 .read_signal_strength = dst_read_signal_strength,
@@ -1469,7 +1479,7 @@ static struct dvb_frontend_ops dst_dvbs_ops = {
1469 1479
1470 .release = dst_release, 1480 .release = dst_release,
1471 .init = dst_init, 1481 .init = dst_init,
1472 .set_frontend = dst_set_frontend, 1482 .tune = dst_set_frontend,
1473 .get_frontend = dst_get_frontend, 1483 .get_frontend = dst_get_frontend,
1474 .read_status = dst_read_status, 1484 .read_status = dst_read_status,
1475 .read_signal_strength = dst_read_signal_strength, 1485 .read_signal_strength = dst_read_signal_strength,
@@ -1496,7 +1506,7 @@ static struct dvb_frontend_ops dst_dvbc_ops = {
1496 1506
1497 .release = dst_release, 1507 .release = dst_release,
1498 .init = dst_init, 1508 .init = dst_init,
1499 .set_frontend = dst_set_frontend, 1509 .tune = dst_set_frontend,
1500 .get_frontend = dst_get_frontend, 1510 .get_frontend = dst_get_frontend,
1501 .read_status = dst_read_status, 1511 .read_status = dst_read_status,
1502 .read_signal_strength = dst_read_signal_strength, 1512 .read_signal_strength = dst_read_signal_strength,
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
index 95ea5095e07e..9b5fa540e1e7 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -92,6 +92,7 @@ static DECLARE_MUTEX(frontend_mutex);
92 92
93struct dvb_frontend_private { 93struct dvb_frontend_private {
94 94
95 /* thread/frontend values */
95 struct dvb_device *dvbdev; 96 struct dvb_device *dvbdev;
96 struct dvb_frontend_parameters parameters; 97 struct dvb_frontend_parameters parameters;
97 struct dvb_fe_events events; 98 struct dvb_fe_events events;
@@ -100,20 +101,25 @@ struct dvb_frontend_private {
100 wait_queue_head_t wait_queue; 101 wait_queue_head_t wait_queue;
101 pid_t thread_pid; 102 pid_t thread_pid;
102 unsigned long release_jiffies; 103 unsigned long release_jiffies;
103 int state; 104 unsigned int exit;
104 int bending; 105 unsigned int wakeup;
105 int lnb_drift;
106 int inversion;
107 int auto_step;
108 int auto_sub_step;
109 int started_auto_step;
110 int min_delay;
111 int max_drift;
112 int step_size;
113 int exit;
114 int wakeup;
115 fe_status_t status; 106 fe_status_t status;
116 fe_sec_tone_mode_t tone; 107 unsigned int tune_mode_flags;
108 unsigned int delay;
109
110 /* swzigzag values */
111 unsigned int state;
112 unsigned int bending;
113 int lnb_drift;
114 unsigned int inversion;
115 unsigned int auto_step;
116 unsigned int auto_sub_step;
117 unsigned int started_auto_step;
118 unsigned int min_delay;
119 unsigned int max_drift;
120 unsigned int step_size;
121 int quality;
122 unsigned int check_wrapped;
117}; 123};
118 124
119 125
@@ -208,21 +214,21 @@ static void dvb_frontend_init(struct dvb_frontend *fe)
208 fe->ops->init(fe); 214 fe->ops->init(fe);
209} 215}
210 216
211static void update_delay(int *quality, int *delay, int min_delay, int locked) 217static void dvb_frontend_swzigzag_update_delay(struct dvb_frontend_private *fepriv, int locked)
212{ 218{
213 int q2; 219 int q2;
214 220
215 dprintk ("%s\n", __FUNCTION__); 221 dprintk ("%s\n", __FUNCTION__);
216 222
217 if (locked) 223 if (locked)
218 (*quality) = (*quality * 220 + 36*256) / 256; 224 (fepriv->quality) = (fepriv->quality * 220 + 36*256) / 256;
219 else 225 else
220 (*quality) = (*quality * 220 + 0) / 256; 226 (fepriv->quality) = (fepriv->quality * 220 + 0) / 256;
221 227
222 q2 = *quality - 128; 228 q2 = fepriv->quality - 128;
223 q2 *= q2; 229 q2 *= q2;
224 230
225 *delay = min_delay + q2 * HZ / (128*128); 231 fepriv->delay = fepriv->min_delay + q2 * HZ / (128*128);
226} 232}
227 233
228/** 234/**
@@ -232,7 +238,7 @@ static void update_delay(int *quality, int *delay, int min_delay, int locked)
232 * @param check_wrapped Checks if an iteration has completed. DO NOT SET ON THE FIRST ATTEMPT 238 * @param check_wrapped Checks if an iteration has completed. DO NOT SET ON THE FIRST ATTEMPT
233 * @returns Number of complete iterations that have been performed. 239 * @returns Number of complete iterations that have been performed.
234 */ 240 */
235static int dvb_frontend_autotune(struct dvb_frontend *fe, int check_wrapped) 241static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wrapped)
236{ 242{
237 int autoinversion; 243 int autoinversion;
238 int ready = 0; 244 int ready = 0;
@@ -321,6 +327,129 @@ static int dvb_frontend_autotune(struct dvb_frontend *fe, int check_wrapped)
321 return 0; 327 return 0;
322} 328}
323 329
330static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
331{
332 fe_status_t s;
333 struct dvb_frontend_private *fepriv = fe->frontend_priv;
334
335 /* if we've got no parameters, just keep idling */
336 if (fepriv->state & FESTATE_IDLE) {
337 fepriv->delay = 3*HZ;
338 fepriv->quality = 0;
339 return;
340 }
341
342 /* in SCAN mode, we just set the frontend when asked and leave it alone */
343 if (fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT) {
344 if (fepriv->state & FESTATE_RETUNE) {
345 if (fe->ops->set_frontend)
346 fe->ops->set_frontend(fe, &fepriv->parameters);
347 fepriv->state = FESTATE_TUNED;
348 }
349 fepriv->delay = 3*HZ;
350 fepriv->quality = 0;
351 return;
352 }
353
354 /* get the frontend status */
355 if (fepriv->state & FESTATE_RETUNE) {
356 s = 0;
357 } else {
358 if (fe->ops->read_status)
359 fe->ops->read_status(fe, &s);
360 if (s != fepriv->status) {
361 dvb_frontend_add_event(fe, s);
362 fepriv->status = s;
363 }
364 }
365
366 /* if we're not tuned, and we have a lock, move to the TUNED state */
367 if ((fepriv->state & FESTATE_WAITFORLOCK) && (s & FE_HAS_LOCK)) {
368 dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
369 fepriv->state = FESTATE_TUNED;
370
371 /* if we're tuned, then we have determined the correct inversion */
372 if ((!(fe->ops->info.caps & FE_CAN_INVERSION_AUTO)) &&
373 (fepriv->parameters.inversion == INVERSION_AUTO)) {
374 fepriv->parameters.inversion = fepriv->inversion;
375 }
376 return;
377 }
378
379 /* if we are tuned already, check we're still locked */
380 if (fepriv->state & FESTATE_TUNED) {
381 dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
382
383 /* we're tuned, and the lock is still good... */
384 if (s & FE_HAS_LOCK) {
385 return;
386 } else { /* if we _WERE_ tuned, but now don't have a lock */
387 fepriv->state = FESTATE_ZIGZAG_FAST;
388 fepriv->started_auto_step = fepriv->auto_step;
389 fepriv->check_wrapped = 0;
390 }
391 }
392
393 /* don't actually do anything if we're in the LOSTLOCK state,
394 * the frontend is set to FE_CAN_RECOVER, and the max_drift is 0 */
395 if ((fepriv->state & FESTATE_LOSTLOCK) &&
396 (fe->ops->info.caps & FE_CAN_RECOVER) && (fepriv->max_drift == 0)) {
397 dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
398 return;
399 }
400
401 /* don't do anything if we're in the DISEQC state, since this
402 * might be someone with a motorized dish controlled by DISEQC.
403 * If its actually a re-tune, there will be a SET_FRONTEND soon enough. */
404 if (fepriv->state & FESTATE_DISEQC) {
405 dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
406 return;
407 }
408
409 /* if we're in the RETUNE state, set everything up for a brand
410 * new scan, keeping the current inversion setting, as the next
411 * tune is _very_ likely to require the same */
412 if (fepriv->state & FESTATE_RETUNE) {
413 fepriv->lnb_drift = 0;
414 fepriv->auto_step = 0;
415 fepriv->auto_sub_step = 0;
416 fepriv->started_auto_step = 0;
417 fepriv->check_wrapped = 0;
418 }
419
420 /* fast zigzag. */
421 if ((fepriv->state & FESTATE_SEARCHING_FAST) || (fepriv->state & FESTATE_RETUNE)) {
422 fepriv->delay = fepriv->min_delay;
423
424 /* peform a tune */
425 if (dvb_frontend_swzigzag_autotune(fe, fepriv->check_wrapped)) {
426 /* OK, if we've run out of trials at the fast speed.
427 * Drop back to slow for the _next_ attempt */
428 fepriv->state = FESTATE_SEARCHING_SLOW;
429 fepriv->started_auto_step = fepriv->auto_step;
430 return;
431 }
432 fepriv->check_wrapped = 1;
433
434 /* if we've just retuned, enter the ZIGZAG_FAST state.
435 * This ensures we cannot return from an
436 * FE_SET_FRONTEND ioctl before the first frontend tune
437 * occurs */
438 if (fepriv->state & FESTATE_RETUNE) {
439 fepriv->state = FESTATE_TUNING_FAST;
440 }
441 }
442
443 /* slow zigzag */
444 if (fepriv->state & FESTATE_SEARCHING_SLOW) {
445 dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
446
447 /* Note: don't bother checking for wrapping; we stay in this
448 * state until we get a lock */
449 dvb_frontend_swzigzag_autotune(fe, 0);
450 }
451}
452
324static int dvb_frontend_is_exiting(struct dvb_frontend *fe) 453static int dvb_frontend_is_exiting(struct dvb_frontend *fe)
325{ 454{
326 struct dvb_frontend_private *fepriv = fe->frontend_priv; 455 struct dvb_frontend_private *fepriv = fe->frontend_priv;
@@ -330,7 +459,7 @@ static int dvb_frontend_is_exiting(struct dvb_frontend *fe)
330 459
331 if (fepriv->dvbdev->writers == 1) 460 if (fepriv->dvbdev->writers == 1)
332 if (time_after(jiffies, fepriv->release_jiffies + 461 if (time_after(jiffies, fepriv->release_jiffies +
333 dvb_shutdown_timeout * HZ)) 462 dvb_shutdown_timeout * HZ))
334 return 1; 463 return 1;
335 464
336 return 0; 465 return 0;
@@ -355,18 +484,14 @@ static void dvb_frontend_wakeup(struct dvb_frontend *fe)
355 wake_up_interruptible(&fepriv->wait_queue); 484 wake_up_interruptible(&fepriv->wait_queue);
356} 485}
357 486
358/*
359 * FIXME: use linux/kthread.h
360 */
361static int dvb_frontend_thread(void *data) 487static int dvb_frontend_thread(void *data)
362{ 488{
363 struct dvb_frontend *fe = data; 489 struct dvb_frontend *fe = data;
364 struct dvb_frontend_private *fepriv = fe->frontend_priv; 490 struct dvb_frontend_private *fepriv = fe->frontend_priv;
365 unsigned long timeout; 491 unsigned long timeout;
366 char name [15]; 492 char name [15];
367 int quality = 0, delay = 3*HZ;
368 fe_status_t s; 493 fe_status_t s;
369 int check_wrapped = 0; 494 struct dvb_frontend_parameters *params;
370 495
371 dprintk("%s\n", __FUNCTION__); 496 dprintk("%s\n", __FUNCTION__);
372 497
@@ -377,6 +502,9 @@ static int dvb_frontend_thread(void *data)
377 sigfillset(&current->blocked); 502 sigfillset(&current->blocked);
378 unlock_kernel(); 503 unlock_kernel();
379 504
505 fepriv->check_wrapped = 0;
506 fepriv->quality = 0;
507 fepriv->delay = 3*HZ;
380 fepriv->status = 0; 508 fepriv->status = 0;
381 dvb_frontend_init(fe); 509 dvb_frontend_init(fe);
382 fepriv->wakeup = 0; 510 fepriv->wakeup = 0;
@@ -386,7 +514,7 @@ static int dvb_frontend_thread(void *data)
386 514
387 timeout = wait_event_interruptible_timeout(fepriv->wait_queue, 515 timeout = wait_event_interruptible_timeout(fepriv->wait_queue,
388 dvb_frontend_should_wakeup(fe), 516 dvb_frontend_should_wakeup(fe),
389 delay); 517 fepriv->delay);
390 if (0 != dvb_frontend_is_exiting(fe)) { 518 if (0 != dvb_frontend_is_exiting(fe)) {
391 /* got signal or quitting */ 519 /* got signal or quitting */
392 break; 520 break;
@@ -397,108 +525,22 @@ static int dvb_frontend_thread(void *data)
397 if (down_interruptible(&fepriv->sem)) 525 if (down_interruptible(&fepriv->sem))
398 break; 526 break;
399 527
400 /* if we've got no parameters, just keep idling */ 528 /* do an iteration of the tuning loop */
401 if (fepriv->state & FESTATE_IDLE) { 529 if (fe->ops->tune) {
402 delay = 3*HZ; 530 /* have we been asked to retune? */
403 quality = 0; 531 params = NULL;
404 continue; 532 if (fepriv->state & FESTATE_RETUNE) {
405 } 533 params = &fepriv->parameters;
534 fepriv->state = FESTATE_TUNED;
535 }
406 536
407 /* get the frontend status */ 537 fe->ops->tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s);
408 if (fepriv->state & FESTATE_RETUNE) {
409 s = 0;
410 } else {
411 if (fe->ops->read_status)
412 fe->ops->read_status(fe, &s);
413 if (s != fepriv->status) { 538 if (s != fepriv->status) {
414 dvb_frontend_add_event(fe, s); 539 dvb_frontend_add_event(fe, s);
415 fepriv->status = s; 540 fepriv->status = s;
416 } 541 }
417 } 542 } else {
418 /* if we're not tuned, and we have a lock, move to the TUNED state */ 543 dvb_frontend_swzigzag(fe);
419 if ((fepriv->state & FESTATE_WAITFORLOCK) && (s & FE_HAS_LOCK)) {
420 update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK);
421 fepriv->state = FESTATE_TUNED;
422
423 /* if we're tuned, then we have determined the correct inversion */
424 if ((!(fe->ops->info.caps & FE_CAN_INVERSION_AUTO)) &&
425 (fepriv->parameters.inversion == INVERSION_AUTO)) {
426 fepriv->parameters.inversion = fepriv->inversion;
427 }
428 continue;
429 }
430
431 /* if we are tuned already, check we're still locked */
432 if (fepriv->state & FESTATE_TUNED) {
433 update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK);
434
435 /* we're tuned, and the lock is still good... */
436 if (s & FE_HAS_LOCK)
437 continue;
438 else { /* if we _WERE_ tuned, but now don't have a lock */
439 fepriv->state = FESTATE_ZIGZAG_FAST;
440 fepriv->started_auto_step = fepriv->auto_step;
441 check_wrapped = 0;
442 }
443 }
444
445 /* don't actually do anything if we're in the LOSTLOCK state,
446 * the frontend is set to FE_CAN_RECOVER, and the max_drift is 0 */
447 if ((fepriv->state & FESTATE_LOSTLOCK) &&
448 (fe->ops->info.caps & FE_CAN_RECOVER) && (fepriv->max_drift == 0)) {
449 update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK);
450 continue;
451 }
452
453 /* don't do anything if we're in the DISEQC state, since this
454 * might be someone with a motorized dish controlled by DISEQC.
455 * If its actually a re-tune, there will be a SET_FRONTEND soon enough. */
456 if (fepriv->state & FESTATE_DISEQC) {
457 update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK);
458 continue;
459 }
460
461 /* if we're in the RETUNE state, set everything up for a brand
462 * new scan, keeping the current inversion setting, as the next
463 * tune is _very_ likely to require the same */
464 if (fepriv->state & FESTATE_RETUNE) {
465 fepriv->lnb_drift = 0;
466 fepriv->auto_step = 0;
467 fepriv->auto_sub_step = 0;
468 fepriv->started_auto_step = 0;
469 check_wrapped = 0;
470 }
471
472 /* fast zigzag. */
473 if ((fepriv->state & FESTATE_SEARCHING_FAST) || (fepriv->state & FESTATE_RETUNE)) {
474 delay = fepriv->min_delay;
475
476 /* peform a tune */
477 if (dvb_frontend_autotune(fe, check_wrapped)) {
478 /* OK, if we've run out of trials at the fast speed.
479 * Drop back to slow for the _next_ attempt */
480 fepriv->state = FESTATE_SEARCHING_SLOW;
481 fepriv->started_auto_step = fepriv->auto_step;
482 continue;
483 }
484 check_wrapped = 1;
485
486 /* if we've just retuned, enter the ZIGZAG_FAST state.
487 * This ensures we cannot return from an
488 * FE_SET_FRONTEND ioctl before the first frontend tune
489 * occurs */
490 if (fepriv->state & FESTATE_RETUNE) {
491 fepriv->state = FESTATE_TUNING_FAST;
492 }
493 }
494
495 /* slow zigzag */
496 if (fepriv->state & FESTATE_SEARCHING_SLOW) {
497 update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK);
498
499 /* Note: don't bother checking for wrapping; we stay in this
500 * state until we get a lock */
501 dvb_frontend_autotune(fe, 0);
502 } 544 }
503 } 545 }
504 546
@@ -733,7 +775,6 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
733 err = fe->ops->set_tone(fe, (fe_sec_tone_mode_t) parg); 775 err = fe->ops->set_tone(fe, (fe_sec_tone_mode_t) parg);
734 fepriv->state = FESTATE_DISEQC; 776 fepriv->state = FESTATE_DISEQC;
735 fepriv->status = 0; 777 fepriv->status = 0;
736 fepriv->tone = (fe_sec_tone_mode_t) parg;
737 } 778 }
738 break; 779 break;
739 780
@@ -891,6 +932,10 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
891 err = fe->ops->get_frontend(fe, (struct dvb_frontend_parameters*) parg); 932 err = fe->ops->get_frontend(fe, (struct dvb_frontend_parameters*) parg);
892 } 933 }
893 break; 934 break;
935
936 case FE_SET_FRONTEND_TUNE_MODE:
937 fepriv->tune_mode_flags = (unsigned int) parg;
938 break;
894 }; 939 };
895 940
896 up (&fepriv->sem); 941 up (&fepriv->sem);
@@ -932,6 +977,9 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
932 977
933 /* empty event queue */ 978 /* empty event queue */
934 fepriv->events.eventr = fepriv->events.eventw = 0; 979 fepriv->events.eventr = fepriv->events.eventw = 0;
980
981 /* normal tune mode when opened R/W */
982 fepriv->tune_mode_flags &= ~FE_TUNE_MODE_ONESHOT;
935 } 983 }
936 984
937 return ret; 985 return ret;
@@ -990,7 +1038,6 @@ int dvb_register_frontend(struct dvb_adapter* dvb,
990 init_MUTEX (&fepriv->events.sem); 1038 init_MUTEX (&fepriv->events.sem);
991 fe->dvb = dvb; 1039 fe->dvb = dvb;
992 fepriv->inversion = INVERSION_OFF; 1040 fepriv->inversion = INVERSION_OFF;
993 fepriv->tone = SEC_TONE_OFF;
994 1041
995 printk ("DVB: registering frontend %i (%s)...\n", 1042 printk ("DVB: registering frontend %i (%s)...\n",
996 fe->dvb->num, 1043 fe->dvb->num,
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h
index 1e0840d02f1f..48c3f81be912 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.h
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.h
@@ -58,10 +58,19 @@ struct dvb_frontend_ops {
58 int (*init)(struct dvb_frontend* fe); 58 int (*init)(struct dvb_frontend* fe);
59 int (*sleep)(struct dvb_frontend* fe); 59 int (*sleep)(struct dvb_frontend* fe);
60 60
61 /* if this is set, it overrides the default swzigzag */
62 int (*tune)(struct dvb_frontend* fe,
63 struct dvb_frontend_parameters* params,
64 unsigned int mode_flags,
65 int *delay,
66 fe_status_t *status);
67
68 /* these two are only used for the swzigzag code */
61 int (*set_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); 69 int (*set_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
62 int (*get_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
63 int (*get_tune_settings)(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* settings); 70 int (*get_tune_settings)(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* settings);
64 71
72 int (*get_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
73
65 int (*read_status)(struct dvb_frontend* fe, fe_status_t* status); 74 int (*read_status)(struct dvb_frontend* fe, fe_status_t* status);
66 int (*read_ber)(struct dvb_frontend* fe, u32* ber); 75 int (*read_ber)(struct dvb_frontend* fe, u32* ber);
67 int (*read_signal_strength)(struct dvb_frontend* fe, u16* strength); 76 int (*read_signal_strength)(struct dvb_frontend* fe, u16* strength);
diff --git a/include/linux/dvb/frontend.h b/include/linux/dvb/frontend.h
index d41df7047ed7..c8cbd90ba375 100644
--- a/include/linux/dvb/frontend.h
+++ b/include/linux/dvb/frontend.h
@@ -240,6 +240,15 @@ struct dvb_frontend_event {
240}; 240};
241 241
242 242
243/**
244 * When set, this flag will disable any zigzagging or other "normal" tuning
245 * behaviour. Additionally, there will be no automatic monitoring of the lock
246 * status, and hence no frontend events will be generated. If a frontend device
247 * is closed, this flag will be automatically turned off when the device is
248 * reopened read-write.
249 */
250#define FE_TUNE_MODE_ONESHOT 0x01
251
243 252
244#define FE_GET_INFO _IOR('o', 61, struct dvb_frontend_info) 253#define FE_GET_INFO _IOR('o', 61, struct dvb_frontend_info)
245 254
@@ -260,6 +269,7 @@ struct dvb_frontend_event {
260 269
261#define FE_SET_FRONTEND _IOW('o', 76, struct dvb_frontend_parameters) 270#define FE_SET_FRONTEND _IOW('o', 76, struct dvb_frontend_parameters)
262#define FE_GET_FRONTEND _IOR('o', 77, struct dvb_frontend_parameters) 271#define FE_GET_FRONTEND _IOR('o', 77, struct dvb_frontend_parameters)
272#define FE_SET_FRONTEND_TUNE_MODE _IO('o', 81) /* unsigned int */
263#define FE_GET_EVENT _IOR('o', 78, struct dvb_frontend_event) 273#define FE_GET_EVENT _IOR('o', 78, struct dvb_frontend_event)
264 274
265#define FE_DISHNETWORK_SEND_LEGACY_CMD _IO('o', 80) /* unsigned int */ 275#define FE_DISHNETWORK_SEND_LEGACY_CMD _IO('o', 80) /* unsigned int */