blob: ebc78157b9b8ced38cf637b9c336a0009f868836 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * dvb_frontend.c: DVB frontend tuning interface/thread
3 *
4 *
5 * Copyright (C) 1999-2001 Ralph Metzler
6 * Marcus Metzler
7 * Holger Waechtler
8 * for convergence integrated media GmbH
9 *
10 * Copyright (C) 2004 Andrew de Quincey (tuning thread cleanup)
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
26 */
27
28#include <linux/string.h>
29#include <linux/kernel.h>
30#include <linux/sched.h>
31#include <linux/wait.h>
32#include <linux/slab.h>
33#include <linux/poll.h>
34#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#include <linux/list.h>
Nigel Cunningham7dfb7102006-12-06 20:34:23 -080036#include <linux/freezer.h>
Johannes Stezenbachcc89c222005-06-23 22:02:39 -070037#include <linux/jiffies.h>
Herbert Poetzl8eec1422007-02-08 14:32:43 -030038#include <linux/kthread.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#include <asm/processor.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070040
41#include "dvb_frontend.h"
42#include "dvbdev.h"
Steven Totheacf8d82008-09-26 00:29:49 -030043#include <linux/dvb/version.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070044
45static int dvb_frontend_debug;
Oliver Endriss849be2c2007-08-25 12:22:16 -030046static int dvb_shutdown_timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -070047static int dvb_force_auto_inversion;
48static int dvb_override_tune_delay;
49static int dvb_powerdown_on_sleep = 1;
Darron Broad59b18422008-10-11 11:44:05 -030050static int dvb_mfe_wait_time = 5;
Linus Torvalds1da177e2005-04-16 15:20:36 -070051
52module_param_named(frontend_debug, dvb_frontend_debug, int, 0644);
Johannes Stezenbachf4f009a2005-05-16 21:54:21 -070053MODULE_PARM_DESC(frontend_debug, "Turn on/off frontend core debugging (default:off).");
Manu Abraham6baad3f2006-02-27 00:09:32 -030054module_param(dvb_shutdown_timeout, int, 0644);
Linus Torvalds1da177e2005-04-16 15:20:36 -070055MODULE_PARM_DESC(dvb_shutdown_timeout, "wait <shutdown_timeout> seconds after close() before suspending hardware");
Manu Abraham6baad3f2006-02-27 00:09:32 -030056module_param(dvb_force_auto_inversion, int, 0644);
Linus Torvalds1da177e2005-04-16 15:20:36 -070057MODULE_PARM_DESC(dvb_force_auto_inversion, "0: normal (default), 1: INVERSION_AUTO forced always");
Manu Abraham6baad3f2006-02-27 00:09:32 -030058module_param(dvb_override_tune_delay, int, 0644);
Linus Torvalds1da177e2005-04-16 15:20:36 -070059MODULE_PARM_DESC(dvb_override_tune_delay, "0: normal (default), >0 => delay in milliseconds to wait for lock after a tune attempt");
Manu Abraham6baad3f2006-02-27 00:09:32 -030060module_param(dvb_powerdown_on_sleep, int, 0644);
Uwe Buglaa85585772006-04-11 10:21:37 -030061MODULE_PARM_DESC(dvb_powerdown_on_sleep, "0: do not power down, 1: turn LNB voltage off on sleep (default)");
Darron Broad59b18422008-10-11 11:44:05 -030062module_param(dvb_mfe_wait_time, int, 0644);
63MODULE_PARM_DESC(dvb_mfe_wait_time, "Wait up to <mfe_wait_time> seconds on open() for multi-frontend to become available (default:5 seconds)");
Linus Torvalds1da177e2005-04-16 15:20:36 -070064
65#define dprintk if (dvb_frontend_debug) printk
66
67#define FESTATE_IDLE 1
68#define FESTATE_RETUNE 2
69#define FESTATE_TUNING_FAST 4
70#define FESTATE_TUNING_SLOW 8
71#define FESTATE_TUNED 16
72#define FESTATE_ZIGZAG_FAST 32
73#define FESTATE_ZIGZAG_SLOW 64
74#define FESTATE_DISEQC 128
75#define FESTATE_WAITFORLOCK (FESTATE_TUNING_FAST | FESTATE_TUNING_SLOW | FESTATE_ZIGZAG_FAST | FESTATE_ZIGZAG_SLOW | FESTATE_DISEQC)
76#define FESTATE_SEARCHING_FAST (FESTATE_TUNING_FAST | FESTATE_ZIGZAG_FAST)
77#define FESTATE_SEARCHING_SLOW (FESTATE_TUNING_SLOW | FESTATE_ZIGZAG_SLOW)
78#define FESTATE_LOSTLOCK (FESTATE_ZIGZAG_FAST | FESTATE_ZIGZAG_SLOW)
Manu Abraham0249ef12006-06-21 10:27:31 -030079
80#define FE_ALGO_HW 1
Linus Torvalds1da177e2005-04-16 15:20:36 -070081/*
82 * FESTATE_IDLE. No tuning parameters have been supplied and the loop is idling.
83 * FESTATE_RETUNE. Parameters have been supplied, but we have not yet performed the first tune.
84 * FESTATE_TUNING_FAST. Tuning parameters have been supplied and fast zigzag scan is in progress.
85 * FESTATE_TUNING_SLOW. Tuning parameters have been supplied. Fast zigzag failed, so we're trying again, but slower.
86 * FESTATE_TUNED. The frontend has successfully locked on.
87 * FESTATE_ZIGZAG_FAST. The lock has been lost, and a fast zigzag has been initiated to try and regain it.
88 * FESTATE_ZIGZAG_SLOW. The lock has been lost. Fast zigzag has been failed, so we're trying again, but slower.
89 * FESTATE_DISEQC. A DISEQC command has just been issued.
90 * FESTATE_WAITFORLOCK. When we're waiting for a lock.
91 * FESTATE_SEARCHING_FAST. When we're searching for a signal using a fast zigzag scan.
92 * FESTATE_SEARCHING_SLOW. When we're searching for a signal using a slow zigzag scan.
93 * FESTATE_LOSTLOCK. When the lock has been lost, and we're searching it again.
94 */
95
Ingo Molnar3593cab2006-02-07 06:49:14 -020096static DEFINE_MUTEX(frontend_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070097
98struct dvb_frontend_private {
99
Andrew de Quincey36cb5572006-01-09 15:25:07 -0200100 /* thread/frontend values */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101 struct dvb_device *dvbdev;
102 struct dvb_frontend_parameters parameters;
103 struct dvb_fe_events events;
104 struct semaphore sem;
105 struct list_head list_head;
106 wait_queue_head_t wait_queue;
Herbert Poetzl8eec1422007-02-08 14:32:43 -0300107 struct task_struct *thread;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108 unsigned long release_jiffies;
Andrew de Quincey36cb5572006-01-09 15:25:07 -0200109 unsigned int exit;
110 unsigned int wakeup;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 fe_status_t status;
Peter Beutner400b7082006-01-09 15:32:43 -0200112 unsigned long tune_mode_flags;
Andrew de Quincey36cb5572006-01-09 15:25:07 -0200113 unsigned int delay;
Andrew de Quincey86f40cc2006-03-30 15:53:35 -0300114 unsigned int reinitialise;
Andrew de Quincey64454012006-04-06 14:32:23 -0300115 int tone;
116 int voltage;
Andrew de Quincey36cb5572006-01-09 15:25:07 -0200117
118 /* swzigzag values */
119 unsigned int state;
120 unsigned int bending;
121 int lnb_drift;
122 unsigned int inversion;
123 unsigned int auto_step;
124 unsigned int auto_sub_step;
125 unsigned int started_auto_step;
126 unsigned int min_delay;
127 unsigned int max_drift;
128 unsigned int step_size;
129 int quality;
130 unsigned int check_wrapped;
Manu Abrahamc59e7872008-10-14 16:34:07 -0300131 enum dvbfe_search algo_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132};
133
Andrew de Quincey86f40cc2006-03-30 15:53:35 -0300134static void dvb_frontend_wakeup(struct dvb_frontend *fe);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135
136static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status)
137{
Johannes Stezenbach0c53c702005-05-16 21:54:24 -0700138 struct dvb_frontend_private *fepriv = fe->frontend_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139 struct dvb_fe_events *events = &fepriv->events;
140 struct dvb_frontend_event *e;
141 int wp;
142
Harvey Harrison46b4f7c2008-04-08 23:20:00 -0300143 dprintk ("%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144
Matthias Kaehlcke03b76122007-07-30 14:58:10 -0300145 if (mutex_lock_interruptible (&events->mtx))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146 return;
147
148 wp = (events->eventw + 1) % MAX_EVENT;
149
150 if (wp == events->eventr) {
151 events->overflow = 1;
152 events->eventr = (events->eventr + 1) % MAX_EVENT;
153 }
154
155 e = &events->events[events->eventw];
156
157 memcpy (&e->parameters, &fepriv->parameters,
158 sizeof (struct dvb_frontend_parameters));
159
160 if (status & FE_HAS_LOCK)
Patrick Boettcherdea74862006-05-14 05:01:31 -0300161 if (fe->ops.get_frontend)
162 fe->ops.get_frontend(fe, &e->parameters);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163
164 events->eventw = wp;
165
Matthias Kaehlcke03b76122007-07-30 14:58:10 -0300166 mutex_unlock(&events->mtx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167
168 e->status = status;
169
170 wake_up_interruptible (&events->wait_queue);
171}
172
173static int dvb_frontend_get_event(struct dvb_frontend *fe,
174 struct dvb_frontend_event *event, int flags)
175{
Johannes Stezenbach0c53c702005-05-16 21:54:24 -0700176 struct dvb_frontend_private *fepriv = fe->frontend_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177 struct dvb_fe_events *events = &fepriv->events;
178
Harvey Harrison46b4f7c2008-04-08 23:20:00 -0300179 dprintk ("%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180
181 if (events->overflow) {
182 events->overflow = 0;
183 return -EOVERFLOW;
184 }
185
186 if (events->eventw == events->eventr) {
187 int ret;
188
189 if (flags & O_NONBLOCK)
190 return -EWOULDBLOCK;
191
192 up(&fepriv->sem);
193
194 ret = wait_event_interruptible (events->wait_queue,
195 events->eventw != events->eventr);
196
197 if (down_interruptible (&fepriv->sem))
198 return -ERESTARTSYS;
199
200 if (ret < 0)
201 return ret;
202 }
203
Matthias Kaehlcke03b76122007-07-30 14:58:10 -0300204 if (mutex_lock_interruptible (&events->mtx))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 return -ERESTARTSYS;
206
207 memcpy (event, &events->events[events->eventr],
208 sizeof(struct dvb_frontend_event));
209
210 events->eventr = (events->eventr + 1) % MAX_EVENT;
211
Matthias Kaehlcke03b76122007-07-30 14:58:10 -0300212 mutex_unlock(&events->mtx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213
214 return 0;
215}
216
217static void dvb_frontend_init(struct dvb_frontend *fe)
218{
Steven Toth363c35f2008-10-11 11:05:50 -0300219 dprintk ("DVB: initialising adapter %i frontend %i (%s)...\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 fe->dvb->num,
Steven Toth363c35f2008-10-11 11:05:50 -0300221 fe->id,
Patrick Boettcherdea74862006-05-14 05:01:31 -0300222 fe->ops.info.name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223
Patrick Boettcherdea74862006-05-14 05:01:31 -0300224 if (fe->ops.init)
225 fe->ops.init(fe);
226 if (fe->ops.tuner_ops.init) {
Manu Abraham3b37a152008-10-20 18:14:14 -0300227 if (fe->ops.i2c_gate_ctrl)
228 fe->ops.i2c_gate_ctrl(fe, 1);
Patrick Boettcherdea74862006-05-14 05:01:31 -0300229 fe->ops.tuner_ops.init(fe);
230 if (fe->ops.i2c_gate_ctrl)
231 fe->ops.i2c_gate_ctrl(fe, 0);
Andrew de Quincey7eef5dd2006-04-18 17:47:09 -0300232 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233}
234
Andrew de Quincey86f40cc2006-03-30 15:53:35 -0300235void dvb_frontend_reinitialise(struct dvb_frontend *fe)
236{
237 struct dvb_frontend_private *fepriv = fe->frontend_priv;
238
239 fepriv->reinitialise = 1;
240 dvb_frontend_wakeup(fe);
241}
242EXPORT_SYMBOL(dvb_frontend_reinitialise);
243
Andrew de Quincey36cb5572006-01-09 15:25:07 -0200244static void dvb_frontend_swzigzag_update_delay(struct dvb_frontend_private *fepriv, int locked)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245{
Andrew de Quincey36cb5572006-01-09 15:25:07 -0200246 int q2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247
Harvey Harrison46b4f7c2008-04-08 23:20:00 -0300248 dprintk ("%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249
Andrew de Quincey36cb5572006-01-09 15:25:07 -0200250 if (locked)
251 (fepriv->quality) = (fepriv->quality * 220 + 36*256) / 256;
252 else
253 (fepriv->quality) = (fepriv->quality * 220 + 0) / 256;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254
Andrew de Quincey36cb5572006-01-09 15:25:07 -0200255 q2 = fepriv->quality - 128;
256 q2 *= q2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257
Andrew de Quincey36cb5572006-01-09 15:25:07 -0200258 fepriv->delay = fepriv->min_delay + q2 * HZ / (128*128);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259}
260
261/**
262 * Performs automatic twiddling of frontend parameters.
263 *
264 * @param fe The frontend concerned.
265 * @param check_wrapped Checks if an iteration has completed. DO NOT SET ON THE FIRST ATTEMPT
266 * @returns Number of complete iterations that have been performed.
267 */
Andrew de Quincey36cb5572006-01-09 15:25:07 -0200268static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wrapped)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269{
270 int autoinversion;
271 int ready = 0;
Johannes Stezenbach0c53c702005-05-16 21:54:24 -0700272 struct dvb_frontend_private *fepriv = fe->frontend_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 int original_inversion = fepriv->parameters.inversion;
274 u32 original_frequency = fepriv->parameters.frequency;
275
276 /* are we using autoinversion? */
Patrick Boettcherdea74862006-05-14 05:01:31 -0300277 autoinversion = ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 (fepriv->parameters.inversion == INVERSION_AUTO));
279
280 /* setup parameters correctly */
281 while(!ready) {
282 /* calculate the lnb_drift */
283 fepriv->lnb_drift = fepriv->auto_step * fepriv->step_size;
284
285 /* wrap the auto_step if we've exceeded the maximum drift */
286 if (fepriv->lnb_drift > fepriv->max_drift) {
287 fepriv->auto_step = 0;
288 fepriv->auto_sub_step = 0;
289 fepriv->lnb_drift = 0;
290 }
291
292 /* perform inversion and +/- zigzag */
293 switch(fepriv->auto_sub_step) {
294 case 0:
295 /* try with the current inversion and current drift setting */
296 ready = 1;
297 break;
298
299 case 1:
300 if (!autoinversion) break;
301
302 fepriv->inversion = (fepriv->inversion == INVERSION_OFF) ? INVERSION_ON : INVERSION_OFF;
303 ready = 1;
304 break;
305
306 case 2:
307 if (fepriv->lnb_drift == 0) break;
308
309 fepriv->lnb_drift = -fepriv->lnb_drift;
310 ready = 1;
311 break;
312
313 case 3:
314 if (fepriv->lnb_drift == 0) break;
315 if (!autoinversion) break;
316
317 fepriv->inversion = (fepriv->inversion == INVERSION_OFF) ? INVERSION_ON : INVERSION_OFF;
318 fepriv->lnb_drift = -fepriv->lnb_drift;
319 ready = 1;
320 break;
321
322 default:
323 fepriv->auto_step++;
324 fepriv->auto_sub_step = -1; /* it'll be incremented to 0 in a moment */
325 break;
326 }
327
328 if (!ready) fepriv->auto_sub_step++;
329 }
330
331 /* if this attempt would hit where we started, indicate a complete
332 * iteration has occurred */
333 if ((fepriv->auto_step == fepriv->started_auto_step) &&
334 (fepriv->auto_sub_step == 0) && check_wrapped) {
335 return 1;
336 }
337
338 dprintk("%s: drift:%i inversion:%i auto_step:%i "
339 "auto_sub_step:%i started_auto_step:%i\n",
Harvey Harrison46b4f7c2008-04-08 23:20:00 -0300340 __func__, fepriv->lnb_drift, fepriv->inversion,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 fepriv->auto_step, fepriv->auto_sub_step, fepriv->started_auto_step);
342
343 /* set the frontend itself */
344 fepriv->parameters.frequency += fepriv->lnb_drift;
345 if (autoinversion)
346 fepriv->parameters.inversion = fepriv->inversion;
Patrick Boettcherdea74862006-05-14 05:01:31 -0300347 if (fe->ops.set_frontend)
348 fe->ops.set_frontend(fe, &fepriv->parameters);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349
350 fepriv->parameters.frequency = original_frequency;
351 fepriv->parameters.inversion = original_inversion;
352
353 fepriv->auto_sub_step++;
354 return 0;
355}
356
Andrew de Quincey36cb5572006-01-09 15:25:07 -0200357static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
358{
Andrew de Quincey30d94642006-11-16 22:12:40 -0300359 fe_status_t s = 0;
Andrew de Quincey36cb5572006-01-09 15:25:07 -0200360 struct dvb_frontend_private *fepriv = fe->frontend_priv;
361
362 /* if we've got no parameters, just keep idling */
363 if (fepriv->state & FESTATE_IDLE) {
364 fepriv->delay = 3*HZ;
365 fepriv->quality = 0;
366 return;
367 }
368
369 /* in SCAN mode, we just set the frontend when asked and leave it alone */
370 if (fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT) {
371 if (fepriv->state & FESTATE_RETUNE) {
Patrick Boettcherdea74862006-05-14 05:01:31 -0300372 if (fe->ops.set_frontend)
373 fe->ops.set_frontend(fe, &fepriv->parameters);
Andrew de Quincey36cb5572006-01-09 15:25:07 -0200374 fepriv->state = FESTATE_TUNED;
375 }
376 fepriv->delay = 3*HZ;
377 fepriv->quality = 0;
378 return;
379 }
380
381 /* get the frontend status */
382 if (fepriv->state & FESTATE_RETUNE) {
383 s = 0;
384 } else {
Patrick Boettcherdea74862006-05-14 05:01:31 -0300385 if (fe->ops.read_status)
386 fe->ops.read_status(fe, &s);
Andrew de Quincey36cb5572006-01-09 15:25:07 -0200387 if (s != fepriv->status) {
388 dvb_frontend_add_event(fe, s);
389 fepriv->status = s;
390 }
391 }
392
393 /* if we're not tuned, and we have a lock, move to the TUNED state */
394 if ((fepriv->state & FESTATE_WAITFORLOCK) && (s & FE_HAS_LOCK)) {
395 dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
396 fepriv->state = FESTATE_TUNED;
397
398 /* if we're tuned, then we have determined the correct inversion */
Patrick Boettcherdea74862006-05-14 05:01:31 -0300399 if ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) &&
Andrew de Quincey36cb5572006-01-09 15:25:07 -0200400 (fepriv->parameters.inversion == INVERSION_AUTO)) {
401 fepriv->parameters.inversion = fepriv->inversion;
402 }
403 return;
404 }
405
406 /* if we are tuned already, check we're still locked */
407 if (fepriv->state & FESTATE_TUNED) {
408 dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
409
410 /* we're tuned, and the lock is still good... */
411 if (s & FE_HAS_LOCK) {
412 return;
413 } else { /* if we _WERE_ tuned, but now don't have a lock */
414 fepriv->state = FESTATE_ZIGZAG_FAST;
415 fepriv->started_auto_step = fepriv->auto_step;
416 fepriv->check_wrapped = 0;
417 }
418 }
419
420 /* don't actually do anything if we're in the LOSTLOCK state,
421 * the frontend is set to FE_CAN_RECOVER, and the max_drift is 0 */
422 if ((fepriv->state & FESTATE_LOSTLOCK) &&
Patrick Boettcherdea74862006-05-14 05:01:31 -0300423 (fe->ops.info.caps & FE_CAN_RECOVER) && (fepriv->max_drift == 0)) {
Andrew de Quincey36cb5572006-01-09 15:25:07 -0200424 dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
425 return;
426 }
427
428 /* don't do anything if we're in the DISEQC state, since this
429 * might be someone with a motorized dish controlled by DISEQC.
430 * If its actually a re-tune, there will be a SET_FRONTEND soon enough. */
431 if (fepriv->state & FESTATE_DISEQC) {
432 dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
433 return;
434 }
435
436 /* if we're in the RETUNE state, set everything up for a brand
437 * new scan, keeping the current inversion setting, as the next
438 * tune is _very_ likely to require the same */
439 if (fepriv->state & FESTATE_RETUNE) {
440 fepriv->lnb_drift = 0;
441 fepriv->auto_step = 0;
442 fepriv->auto_sub_step = 0;
443 fepriv->started_auto_step = 0;
444 fepriv->check_wrapped = 0;
445 }
446
447 /* fast zigzag. */
448 if ((fepriv->state & FESTATE_SEARCHING_FAST) || (fepriv->state & FESTATE_RETUNE)) {
449 fepriv->delay = fepriv->min_delay;
450
451 /* peform a tune */
452 if (dvb_frontend_swzigzag_autotune(fe, fepriv->check_wrapped)) {
453 /* OK, if we've run out of trials at the fast speed.
454 * Drop back to slow for the _next_ attempt */
455 fepriv->state = FESTATE_SEARCHING_SLOW;
456 fepriv->started_auto_step = fepriv->auto_step;
457 return;
458 }
459 fepriv->check_wrapped = 1;
460
461 /* if we've just retuned, enter the ZIGZAG_FAST state.
462 * This ensures we cannot return from an
463 * FE_SET_FRONTEND ioctl before the first frontend tune
464 * occurs */
465 if (fepriv->state & FESTATE_RETUNE) {
466 fepriv->state = FESTATE_TUNING_FAST;
467 }
468 }
469
470 /* slow zigzag */
471 if (fepriv->state & FESTATE_SEARCHING_SLOW) {
472 dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
473
474 /* Note: don't bother checking for wrapping; we stay in this
475 * state until we get a lock */
476 dvb_frontend_swzigzag_autotune(fe, 0);
477 }
478}
479
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480static int dvb_frontend_is_exiting(struct dvb_frontend *fe)
481{
Johannes Stezenbach0c53c702005-05-16 21:54:24 -0700482 struct dvb_frontend_private *fepriv = fe->frontend_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483
484 if (fepriv->exit)
485 return 1;
486
487 if (fepriv->dvbdev->writers == 1)
Johannes Stezenbachcc89c222005-06-23 22:02:39 -0700488 if (time_after(jiffies, fepriv->release_jiffies +
Andrew de Quincey36cb5572006-01-09 15:25:07 -0200489 dvb_shutdown_timeout * HZ))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 return 1;
491
492 return 0;
493}
494
495static int dvb_frontend_should_wakeup(struct dvb_frontend *fe)
496{
Johannes Stezenbach0c53c702005-05-16 21:54:24 -0700497 struct dvb_frontend_private *fepriv = fe->frontend_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498
499 if (fepriv->wakeup) {
500 fepriv->wakeup = 0;
501 return 1;
502 }
503 return dvb_frontend_is_exiting(fe);
504}
505
506static void dvb_frontend_wakeup(struct dvb_frontend *fe)
507{
Johannes Stezenbach0c53c702005-05-16 21:54:24 -0700508 struct dvb_frontend_private *fepriv = fe->frontend_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509
510 fepriv->wakeup = 1;
511 wake_up_interruptible(&fepriv->wait_queue);
512}
513
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514static int dvb_frontend_thread(void *data)
515{
Johannes Stezenbach0c53c702005-05-16 21:54:24 -0700516 struct dvb_frontend *fe = data;
517 struct dvb_frontend_private *fepriv = fe->frontend_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 unsigned long timeout;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 fe_status_t s;
Manu Abrahamc59e7872008-10-14 16:34:07 -0300520 enum dvbfe_algo algo;
521
Andrew de Quincey36cb5572006-01-09 15:25:07 -0200522 struct dvb_frontend_parameters *params;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523
Harvey Harrison46b4f7c2008-04-08 23:20:00 -0300524 dprintk("%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525
Andrew de Quincey36cb5572006-01-09 15:25:07 -0200526 fepriv->check_wrapped = 0;
527 fepriv->quality = 0;
528 fepriv->delay = 3*HZ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 fepriv->status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 fepriv->wakeup = 0;
Andrew de Quincey04c56d02006-07-10 03:34:14 -0300531 fepriv->reinitialise = 0;
532
533 dvb_frontend_init(fe);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534
Rafael J. Wysocki83144182007-07-17 04:03:35 -0700535 set_freezable();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 while (1) {
537 up(&fepriv->sem); /* is locked when we enter the thread... */
akpm@linux-foundation.org65916912007-02-08 14:36:57 -0300538restart:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 timeout = wait_event_interruptible_timeout(fepriv->wait_queue,
Rafael J. Wysockie42837b2007-10-18 03:04:45 -0700540 dvb_frontend_should_wakeup(fe) || kthread_should_stop()
541 || freezing(current),
Herbert Poetzl8eec1422007-02-08 14:32:43 -0300542 fepriv->delay);
543
544 if (kthread_should_stop() || dvb_frontend_is_exiting(fe)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 /* got signal or quitting */
546 break;
547 }
548
Herbert Poetzl8eec1422007-02-08 14:32:43 -0300549 if (try_to_freeze())
akpm@linux-foundation.org65916912007-02-08 14:36:57 -0300550 goto restart;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551
552 if (down_interruptible(&fepriv->sem))
553 break;
554
Andrew de Quincey86f40cc2006-03-30 15:53:35 -0300555 if (fepriv->reinitialise) {
556 dvb_frontend_init(fe);
Andrew de Quincey64454012006-04-06 14:32:23 -0300557 if (fepriv->tone != -1) {
Patrick Boettcherdea74862006-05-14 05:01:31 -0300558 fe->ops.set_tone(fe, fepriv->tone);
Andrew de Quincey64454012006-04-06 14:32:23 -0300559 }
560 if (fepriv->voltage != -1) {
Patrick Boettcherdea74862006-05-14 05:01:31 -0300561 fe->ops.set_voltage(fe, fepriv->voltage);
Andrew de Quincey64454012006-04-06 14:32:23 -0300562 }
Andrew de Quincey86f40cc2006-03-30 15:53:35 -0300563 fepriv->reinitialise = 0;
564 }
565
Andrew de Quincey36cb5572006-01-09 15:25:07 -0200566 /* do an iteration of the tuning loop */
Manu Abrahamd772bd02006-06-24 11:18:58 -0300567 if (fe->ops.get_frontend_algo) {
Manu Abrahamc59e7872008-10-14 16:34:07 -0300568 algo = fe->ops.get_frontend_algo(fe);
569 switch (algo) {
570 case DVBFE_ALGO_HW:
571 dprintk("%s: Frontend ALGO = DVBFE_ALGO_HW\n", __func__);
572 params = NULL; /* have we been asked to RETUNE ? */
573
Manu Abrahamd772bd02006-06-24 11:18:58 -0300574 if (fepriv->state & FESTATE_RETUNE) {
Manu Abrahamc59e7872008-10-14 16:34:07 -0300575 dprintk("%s: Retune requested, FESTATE_RETUNE\n", __func__);
Matthias Schwarzottf7c9bf92008-10-28 05:58:04 -0300576 params = &fepriv->parameters;
Manu Abrahamd772bd02006-06-24 11:18:58 -0300577 fepriv->state = FESTATE_TUNED;
578 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579
Manu Abrahamc59e7872008-10-14 16:34:07 -0300580 if (fe->ops.tune)
581 fe->ops.tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s);
582
Darron Broad2fac9a02008-12-18 06:27:50 -0300583 if (s != fepriv->status && !(fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT)) {
Manu Abrahamc59e7872008-10-14 16:34:07 -0300584 dprintk("%s: state changed, adding current state\n", __func__);
Manu Abrahamd772bd02006-06-24 11:18:58 -0300585 dvb_frontend_add_event(fe, s);
586 fepriv->status = s;
587 }
Manu Abrahamc59e7872008-10-14 16:34:07 -0300588 break;
589 case DVBFE_ALGO_SW:
590 dprintk("%s: Frontend ALGO = DVBFE_ALGO_SW\n", __func__);
Manu Abraham70d90632006-06-29 22:05:23 -0300591 dvb_frontend_swzigzag(fe);
Manu Abrahamc59e7872008-10-14 16:34:07 -0300592 break;
593 case DVBFE_ALGO_CUSTOM:
594 params = NULL; /* have we been asked to RETUNE ? */
595 dprintk("%s: Frontend ALGO = DVBFE_ALGO_CUSTOM, state=%d\n", __func__, fepriv->state);
596 if (fepriv->state & FESTATE_RETUNE) {
597 dprintk("%s: Retune requested, FESTAT_RETUNE\n", __func__);
Manu Abrahamf04c3ca2008-10-28 06:11:24 -0300598 params = &fepriv->parameters;
Manu Abrahamc59e7872008-10-14 16:34:07 -0300599 fepriv->state = FESTATE_TUNED;
600 }
601 /* Case where we are going to search for a carrier
602 * User asked us to retune again for some reason, possibly
603 * requesting a search with a new set of parameters
604 */
605 if (fepriv->algo_status & DVBFE_ALGO_SEARCH_AGAIN) {
Arvo Jarve7bcbdf32008-10-20 06:05:21 -0300606 if (fe->ops.search) {
Manu Abrahamc59e7872008-10-14 16:34:07 -0300607 fepriv->algo_status = fe->ops.search(fe, &fepriv->parameters);
608 /* We did do a search as was requested, the flags are
609 * now unset as well and has the flags wrt to search.
610 */
Arvo Jarve7bcbdf32008-10-20 06:05:21 -0300611 } else {
612 fepriv->algo_status &= ~DVBFE_ALGO_SEARCH_AGAIN;
613 }
Manu Abrahamc59e7872008-10-14 16:34:07 -0300614 }
615 /* Track the carrier if the search was successful */
616 if (fepriv->algo_status == DVBFE_ALGO_SEARCH_SUCCESS) {
Manu Abrahamc59e7872008-10-14 16:34:07 -0300617 if (fe->ops.track)
618 fe->ops.track(fe, &fepriv->parameters);
Arvo Jarve7bcbdf32008-10-20 06:05:21 -0300619 } else {
620 fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;
621 fepriv->delay = HZ / 2;
622 }
623 fe->ops.read_status(fe, &s);
624 if (s != fepriv->status) {
625 dvb_frontend_add_event(fe, s); /* update event list */
626 fepriv->status = s;
627 if (!(s & FE_HAS_LOCK)) {
628 fepriv->delay = HZ / 10;
629 fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;
630 } else {
631 fepriv->delay = 60 * HZ;
632 }
Manu Abrahamc59e7872008-10-14 16:34:07 -0300633 }
634 break;
635 default:
636 dprintk("%s: UNDEFINED ALGO !\n", __func__);
637 break;
638 }
639 } else {
Manu Abraham4a4edcc2006-06-25 05:46:26 -0300640 dvb_frontend_swzigzag(fe);
Manu Abrahamc59e7872008-10-14 16:34:07 -0300641 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 }
643
Oliver Endriss608f62d2007-08-25 13:17:53 -0300644 if (dvb_powerdown_on_sleep) {
645 if (fe->ops.set_voltage)
646 fe->ops.set_voltage(fe, SEC_VOLTAGE_OFF);
Patrick Boettcherdea74862006-05-14 05:01:31 -0300647 if (fe->ops.tuner_ops.sleep) {
Devin Heitmueller41286d92008-11-16 00:44:52 -0300648 if (fe->ops.i2c_gate_ctrl)
649 fe->ops.i2c_gate_ctrl(fe, 1);
Patrick Boettcherdea74862006-05-14 05:01:31 -0300650 fe->ops.tuner_ops.sleep(fe);
651 if (fe->ops.i2c_gate_ctrl)
652 fe->ops.i2c_gate_ctrl(fe, 0);
Andrew de Quincey7eef5dd2006-04-18 17:47:09 -0300653 }
Patrick Boettcherdea74862006-05-14 05:01:31 -0300654 if (fe->ops.sleep)
655 fe->ops.sleep(fe);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 }
657
Herbert Poetzl8eec1422007-02-08 14:32:43 -0300658 fepriv->thread = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 mb();
660
661 dvb_frontend_wakeup(fe);
662 return 0;
663}
664
665static void dvb_frontend_stop(struct dvb_frontend *fe)
666{
Johannes Stezenbach0c53c702005-05-16 21:54:24 -0700667 struct dvb_frontend_private *fepriv = fe->frontend_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668
Harvey Harrison46b4f7c2008-04-08 23:20:00 -0300669 dprintk ("%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670
671 fepriv->exit = 1;
672 mb();
673
Herbert Poetzl8eec1422007-02-08 14:32:43 -0300674 if (!fepriv->thread)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 return;
676
Herbert Poetzl8eec1422007-02-08 14:32:43 -0300677 kthread_stop(fepriv->thread);
Markus Rechbergerca5be9c2007-04-14 10:18:58 -0300678
Herbert Poetzl8eec1422007-02-08 14:32:43 -0300679 init_MUTEX (&fepriv->sem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 fepriv->state = FESTATE_IDLE;
681
682 /* paranoia check in case a signal arrived */
Herbert Poetzl8eec1422007-02-08 14:32:43 -0300683 if (fepriv->thread)
684 printk("dvb_frontend_stop: warning: thread %p won't exit\n",
685 fepriv->thread);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686}
687
NooneImportant83b75b02005-11-08 21:35:27 -0800688s32 timeval_usec_diff(struct timeval lasttime, struct timeval curtime)
689{
690 return ((curtime.tv_usec < lasttime.tv_usec) ?
691 1000000 - lasttime.tv_usec + curtime.tv_usec :
692 curtime.tv_usec - lasttime.tv_usec);
693}
694EXPORT_SYMBOL(timeval_usec_diff);
695
696static inline void timeval_usec_add(struct timeval *curtime, u32 add_usec)
697{
698 curtime->tv_usec += add_usec;
699 if (curtime->tv_usec >= 1000000) {
700 curtime->tv_usec -= 1000000;
701 curtime->tv_sec++;
702 }
703}
704
705/*
706 * Sleep until gettimeofday() > waketime + add_usec
707 * This needs to be as precise as possible, but as the delay is
708 * usually between 2ms and 32ms, it is done using a scheduled msleep
709 * followed by usleep (normally a busy-wait loop) for the remainder
710 */
711void dvb_frontend_sleep_until(struct timeval *waketime, u32 add_usec)
712{
713 struct timeval lasttime;
714 s32 delta, newdelta;
715
716 timeval_usec_add(waketime, add_usec);
717
718 do_gettimeofday(&lasttime);
719 delta = timeval_usec_diff(lasttime, *waketime);
720 if (delta > 2500) {
721 msleep((delta - 1500) / 1000);
722 do_gettimeofday(&lasttime);
723 newdelta = timeval_usec_diff(lasttime, *waketime);
724 delta = (newdelta > delta) ? 0 : newdelta;
725 }
726 if (delta > 0)
727 udelay(delta);
728}
729EXPORT_SYMBOL(dvb_frontend_sleep_until);
730
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731static int dvb_frontend_start(struct dvb_frontend *fe)
732{
733 int ret;
Johannes Stezenbach0c53c702005-05-16 21:54:24 -0700734 struct dvb_frontend_private *fepriv = fe->frontend_priv;
Herbert Poetzl8eec1422007-02-08 14:32:43 -0300735 struct task_struct *fe_thread;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736
Harvey Harrison46b4f7c2008-04-08 23:20:00 -0300737 dprintk ("%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738
Herbert Poetzl8eec1422007-02-08 14:32:43 -0300739 if (fepriv->thread) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 if (!fepriv->exit)
741 return 0;
742 else
743 dvb_frontend_stop (fe);
744 }
745
746 if (signal_pending(current))
747 return -EINTR;
748 if (down_interruptible (&fepriv->sem))
749 return -EINTR;
750
751 fepriv->state = FESTATE_IDLE;
752 fepriv->exit = 0;
Herbert Poetzl8eec1422007-02-08 14:32:43 -0300753 fepriv->thread = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 mb();
755
Herbert Poetzl8eec1422007-02-08 14:32:43 -0300756 fe_thread = kthread_run(dvb_frontend_thread, fe,
Steven Toth363c35f2008-10-11 11:05:50 -0300757 "kdvb-ad-%i-fe-%i", fe->dvb->num,fe->id);
Herbert Poetzl8eec1422007-02-08 14:32:43 -0300758 if (IS_ERR(fe_thread)) {
759 ret = PTR_ERR(fe_thread);
760 printk("dvb_frontend_start: failed to start kthread (%d)\n", ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 up(&fepriv->sem);
762 return ret;
763 }
Herbert Poetzl8eec1422007-02-08 14:32:43 -0300764 fepriv->thread = fe_thread;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 return 0;
766}
767
Oliver Endrissc471b332007-08-09 01:03:42 -0300768static void dvb_frontend_get_frequeny_limits(struct dvb_frontend *fe,
769 u32 *freq_min, u32 *freq_max)
770{
771 *freq_min = max(fe->ops.info.frequency_min, fe->ops.tuner_ops.info.frequency_min);
772
773 if (fe->ops.info.frequency_max == 0)
774 *freq_max = fe->ops.tuner_ops.info.frequency_max;
775 else if (fe->ops.tuner_ops.info.frequency_max == 0)
776 *freq_max = fe->ops.info.frequency_max;
777 else
778 *freq_max = min(fe->ops.info.frequency_max, fe->ops.tuner_ops.info.frequency_max);
779
780 if (*freq_min == 0 || *freq_max == 0)
Steven Toth363c35f2008-10-11 11:05:50 -0300781 printk(KERN_WARNING "DVB: adapter %i frontend %u frequency limits undefined - fix the driver\n",
782 fe->dvb->num,fe->id);
Oliver Endrissc471b332007-08-09 01:03:42 -0300783}
784
Oliver Endriss1fab46f2007-07-23 21:00:36 -0300785static int dvb_frontend_check_parameters(struct dvb_frontend *fe,
786 struct dvb_frontend_parameters *parms)
787{
Oliver Endrissc471b332007-08-09 01:03:42 -0300788 u32 freq_min;
789 u32 freq_max;
790
Oliver Endriss1fab46f2007-07-23 21:00:36 -0300791 /* range check: frequency */
Oliver Endrissc471b332007-08-09 01:03:42 -0300792 dvb_frontend_get_frequeny_limits(fe, &freq_min, &freq_max);
793 if ((freq_min && parms->frequency < freq_min) ||
794 (freq_max && parms->frequency > freq_max)) {
Steven Toth363c35f2008-10-11 11:05:50 -0300795 printk(KERN_WARNING "DVB: adapter %i frontend %i frequency %u out of range (%u..%u)\n",
796 fe->dvb->num, fe->id, parms->frequency, freq_min, freq_max);
Oliver Endriss1fab46f2007-07-23 21:00:36 -0300797 return -EINVAL;
798 }
799
800 /* range check: symbol rate */
801 if (fe->ops.info.type == FE_QPSK) {
802 if ((fe->ops.info.symbol_rate_min &&
803 parms->u.qpsk.symbol_rate < fe->ops.info.symbol_rate_min) ||
804 (fe->ops.info.symbol_rate_max &&
805 parms->u.qpsk.symbol_rate > fe->ops.info.symbol_rate_max)) {
Steven Toth363c35f2008-10-11 11:05:50 -0300806 printk(KERN_WARNING "DVB: adapter %i frontend %i symbol rate %u out of range (%u..%u)\n",
807 fe->dvb->num, fe->id, parms->u.qpsk.symbol_rate,
Oliver Endriss1fab46f2007-07-23 21:00:36 -0300808 fe->ops.info.symbol_rate_min, fe->ops.info.symbol_rate_max);
809 return -EINVAL;
810 }
811
812 } else if (fe->ops.info.type == FE_QAM) {
813 if ((fe->ops.info.symbol_rate_min &&
814 parms->u.qam.symbol_rate < fe->ops.info.symbol_rate_min) ||
815 (fe->ops.info.symbol_rate_max &&
816 parms->u.qam.symbol_rate > fe->ops.info.symbol_rate_max)) {
Steven Toth363c35f2008-10-11 11:05:50 -0300817 printk(KERN_WARNING "DVB: adapter %i frontend %i symbol rate %u out of range (%u..%u)\n",
818 fe->dvb->num, fe->id, parms->u.qam.symbol_rate,
Oliver Endriss1fab46f2007-07-23 21:00:36 -0300819 fe->ops.info.symbol_rate_min, fe->ops.info.symbol_rate_max);
820 return -EINVAL;
821 }
822 }
823
824 return 0;
825}
826
Mauro Carvalho Chehab072ce0c2009-01-05 01:19:06 -0300827static struct dtv_cmds_h dtv_cmds[] = {
Steven Tothe7fee0f32008-09-11 10:23:01 -0300828 [DTV_TUNE] = {
829 .name = "DTV_TUNE",
830 .cmd = DTV_TUNE,
Steven Toth6b73eea2008-09-04 01:12:25 -0300831 .set = 1,
832 },
Steven Tothe7fee0f32008-09-11 10:23:01 -0300833 [DTV_CLEAR] = {
834 .name = "DTV_CLEAR",
835 .cmd = DTV_CLEAR,
Steven Toth6b73eea2008-09-04 01:12:25 -0300836 .set = 1,
837 },
838
839 /* Set */
Steven Toth363429a2008-09-12 01:34:28 -0300840 [DTV_FREQUENCY] = {
841 .name = "DTV_FREQUENCY",
842 .cmd = DTV_FREQUENCY,
Steven Toth6b73eea2008-09-04 01:12:25 -0300843 .set = 1,
844 },
Steven Toth75b7f942008-09-13 16:56:34 -0300845 [DTV_BANDWIDTH_HZ] = {
846 .name = "DTV_BANDWIDTH_HZ",
847 .cmd = DTV_BANDWIDTH_HZ,
Steven Toth6b73eea2008-09-04 01:12:25 -0300848 .set = 1,
849 },
Steven Toth363429a2008-09-12 01:34:28 -0300850 [DTV_MODULATION] = {
851 .name = "DTV_MODULATION",
852 .cmd = DTV_MODULATION,
Steven Toth6b73eea2008-09-04 01:12:25 -0300853 .set = 1,
854 },
Steven Toth363429a2008-09-12 01:34:28 -0300855 [DTV_INVERSION] = {
856 .name = "DTV_INVERSION",
857 .cmd = DTV_INVERSION,
Steven Toth6b73eea2008-09-04 01:12:25 -0300858 .set = 1,
859 },
Steven Toth363429a2008-09-12 01:34:28 -0300860 [DTV_DISEQC_MASTER] = {
861 .name = "DTV_DISEQC_MASTER",
862 .cmd = DTV_DISEQC_MASTER,
Steven Toth6b73eea2008-09-04 01:12:25 -0300863 .set = 1,
864 .buffer = 1,
865 },
Steven Toth363429a2008-09-12 01:34:28 -0300866 [DTV_SYMBOL_RATE] = {
867 .name = "DTV_SYMBOL_RATE",
868 .cmd = DTV_SYMBOL_RATE,
Steven Toth6b73eea2008-09-04 01:12:25 -0300869 .set = 1,
870 },
Steven Toth363429a2008-09-12 01:34:28 -0300871 [DTV_INNER_FEC] = {
872 .name = "DTV_INNER_FEC",
873 .cmd = DTV_INNER_FEC,
Steven Toth6b73eea2008-09-04 01:12:25 -0300874 .set = 1,
875 },
Steven Toth363429a2008-09-12 01:34:28 -0300876 [DTV_VOLTAGE] = {
877 .name = "DTV_VOLTAGE",
878 .cmd = DTV_VOLTAGE,
Steven Toth6b73eea2008-09-04 01:12:25 -0300879 .set = 1,
880 },
Steven Toth363429a2008-09-12 01:34:28 -0300881 [DTV_TONE] = {
882 .name = "DTV_TONE",
883 .cmd = DTV_TONE,
Steven Toth6b73eea2008-09-04 01:12:25 -0300884 .set = 1,
885 },
Steven Toth363429a2008-09-12 01:34:28 -0300886 [DTV_PILOT] = {
887 .name = "DTV_PILOT",
888 .cmd = DTV_PILOT,
Steven Toth6b73eea2008-09-04 01:12:25 -0300889 .set = 1,
890 },
Steven Toth363429a2008-09-12 01:34:28 -0300891 [DTV_ROLLOFF] = {
892 .name = "DTV_ROLLOFF",
893 .cmd = DTV_ROLLOFF,
Steven Toth6b73eea2008-09-04 01:12:25 -0300894 .set = 1,
895 },
Steven Toth363429a2008-09-12 01:34:28 -0300896 [DTV_DELIVERY_SYSTEM] = {
897 .name = "DTV_DELIVERY_SYSTEM",
898 .cmd = DTV_DELIVERY_SYSTEM,
Steven Toth6b73eea2008-09-04 01:12:25 -0300899 .set = 1,
900 },
Steven Tothef526f42008-10-06 22:01:47 -0300901 [DTV_HIERARCHY] = {
902 .name = "DTV_HIERARCHY",
903 .cmd = DTV_HIERARCHY,
904 .set = 1,
905 },
Steven Totha4de91b2008-10-06 21:55:46 -0300906 [DTV_CODE_RATE_HP] = {
907 .name = "DTV_CODE_RATE_HP",
908 .cmd = DTV_CODE_RATE_HP,
909 .set = 1,
910 },
911 [DTV_CODE_RATE_LP] = {
912 .name = "DTV_CODE_RATE_LP",
913 .cmd = DTV_CODE_RATE_LP,
914 .set = 1,
915 },
Steven Tothb87625f2008-10-06 21:56:59 -0300916 [DTV_GUARD_INTERVAL] = {
917 .name = "DTV_GUARD_INTERVAL",
918 .cmd = DTV_GUARD_INTERVAL,
919 .set = 1,
920 },
921 [DTV_TRANSMISSION_MODE] = {
922 .name = "DTV_TRANSMISSION_MODE",
923 .cmd = DTV_TRANSMISSION_MODE,
924 .set = 1,
925 },
Steven Toth6b73eea2008-09-04 01:12:25 -0300926 /* Get */
Steven Toth363429a2008-09-12 01:34:28 -0300927 [DTV_DISEQC_SLAVE_REPLY] = {
928 .name = "DTV_DISEQC_SLAVE_REPLY",
929 .cmd = DTV_DISEQC_SLAVE_REPLY,
Steven Toth6b73eea2008-09-04 01:12:25 -0300930 .set = 0,
931 .buffer = 1,
932 },
Steven Totheacf8d82008-09-26 00:29:49 -0300933 [DTV_API_VERSION] = {
934 .name = "DTV_API_VERSION",
935 .cmd = DTV_API_VERSION,
936 .set = 0,
937 },
Steven Totha4de91b2008-10-06 21:55:46 -0300938 [DTV_CODE_RATE_HP] = {
939 .name = "DTV_CODE_RATE_HP",
940 .cmd = DTV_CODE_RATE_HP,
941 .set = 0,
942 },
943 [DTV_CODE_RATE_LP] = {
944 .name = "DTV_CODE_RATE_LP",
945 .cmd = DTV_CODE_RATE_LP,
946 .set = 0,
947 },
Steven Tothb87625f2008-10-06 21:56:59 -0300948 [DTV_GUARD_INTERVAL] = {
949 .name = "DTV_GUARD_INTERVAL",
950 .cmd = DTV_GUARD_INTERVAL,
951 .set = 0,
952 },
953 [DTV_TRANSMISSION_MODE] = {
954 .name = "DTV_TRANSMISSION_MODE",
955 .cmd = DTV_TRANSMISSION_MODE,
956 .set = 0,
957 },
Steven Tothef526f42008-10-06 22:01:47 -0300958 [DTV_HIERARCHY] = {
959 .name = "DTV_HIERARCHY",
960 .cmd = DTV_HIERARCHY,
961 .set = 0,
962 },
Steven Toth6b73eea2008-09-04 01:12:25 -0300963};
964
Mauro Carvalho Chehab072ce0c2009-01-05 01:19:06 -0300965static void dtv_property_dump(struct dtv_property *tvp)
Steven Toth6b73eea2008-09-04 01:12:25 -0300966{
967 int i;
968
Steven Toth82d76692008-10-06 20:44:04 -0300969 if (tvp->cmd <= 0 || tvp->cmd > DTV_MAX_COMMAND) {
Steven Totha1bc84c2008-10-17 00:20:19 -0300970 printk(KERN_WARNING "%s: tvp.cmd = 0x%08x undefined\n",
Darron Broad4aae8ef2008-10-03 11:50:00 -0300971 __func__, tvp->cmd);
972 return;
973 }
974
Steven Totha1bc84c2008-10-17 00:20:19 -0300975 dprintk("%s() tvp.cmd = 0x%08x (%s)\n"
976 ,__func__
Steven Toth6b73eea2008-09-04 01:12:25 -0300977 ,tvp->cmd
Steven Toth56f06802008-09-11 10:19:27 -0300978 ,dtv_cmds[ tvp->cmd ].name);
Steven Toth6b73eea2008-09-04 01:12:25 -0300979
Steven Toth56f06802008-09-11 10:19:27 -0300980 if(dtv_cmds[ tvp->cmd ].buffer) {
Steven Toth6b73eea2008-09-04 01:12:25 -0300981
Steven Totha1bc84c2008-10-17 00:20:19 -0300982 dprintk("%s() tvp.u.buffer.len = 0x%02x\n"
983 ,__func__
Steven Toth6b73eea2008-09-04 01:12:25 -0300984 ,tvp->u.buffer.len);
985
986 for(i = 0; i < tvp->u.buffer.len; i++)
Steven Totha1bc84c2008-10-17 00:20:19 -0300987 dprintk("%s() tvp.u.buffer.data[0x%02x] = 0x%02x\n"
988 ,__func__
Steven Toth6b73eea2008-09-04 01:12:25 -0300989 ,i
990 ,tvp->u.buffer.data[i]);
991
992 } else
Steven Totha1bc84c2008-10-17 00:20:19 -0300993 dprintk("%s() tvp.u.data = 0x%08x\n", __func__, tvp->u.data);
Steven Toth6b73eea2008-09-04 01:12:25 -0300994}
995
Mauro Carvalho Chehab072ce0c2009-01-05 01:19:06 -0300996static int is_legacy_delivery_system(fe_delivery_system_t s)
Steven Toth6b73eea2008-09-04 01:12:25 -0300997{
998 if((s == SYS_UNDEFINED) || (s == SYS_DVBC_ANNEX_AC) ||
Devin Heitmueller3fa37de2008-11-16 00:33:32 -0300999 (s == SYS_DVBC_ANNEX_B) || (s == SYS_DVBT) || (s == SYS_DVBS) ||
1000 (s == SYS_ATSC))
Steven Toth6b73eea2008-09-04 01:12:25 -03001001 return 1;
1002
1003 return 0;
1004}
1005
Steven Tothee33c522008-09-11 23:52:32 -03001006/* Synchronise the legacy tuning parameters into the cache, so that demodulator
1007 * drivers can use a single set_frontend tuning function, regardless of whether
1008 * it's being used for the legacy or new API, reducing code and complexity.
1009 */
Mauro Carvalho Chehab072ce0c2009-01-05 01:19:06 -03001010static void dtv_property_cache_sync(struct dvb_frontend *fe,
1011 struct dvb_frontend_parameters *p)
Steven Tothee33c522008-09-11 23:52:32 -03001012{
1013 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
1014
1015 c->frequency = p->frequency;
1016 c->inversion = p->inversion;
1017
1018 switch (fe->ops.info.type) {
1019 case FE_QPSK:
Darron Broade5cefa82008-10-03 11:53:18 -03001020 c->modulation = QPSK; /* implied for DVB-S in legacy API */
1021 c->rolloff = ROLLOFF_35;/* implied for DVB-S */
Steven Tothee33c522008-09-11 23:52:32 -03001022 c->symbol_rate = p->u.qpsk.symbol_rate;
1023 c->fec_inner = p->u.qpsk.fec_inner;
Steven Toth80a773c2008-09-12 00:53:50 -03001024 c->delivery_system = SYS_DVBS;
Steven Tothee33c522008-09-11 23:52:32 -03001025 break;
1026 case FE_QAM:
1027 c->symbol_rate = p->u.qam.symbol_rate;
1028 c->fec_inner = p->u.qam.fec_inner;
1029 c->modulation = p->u.qam.modulation;
Steven Toth80a773c2008-09-12 00:53:50 -03001030 c->delivery_system = SYS_DVBC_ANNEX_AC;
Steven Tothee33c522008-09-11 23:52:32 -03001031 break;
1032 case FE_OFDM:
Steven Toth75b7f942008-09-13 16:56:34 -03001033 if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ)
1034 c->bandwidth_hz = 6000000;
1035 else if (p->u.ofdm.bandwidth == BANDWIDTH_7_MHZ)
1036 c->bandwidth_hz = 7000000;
1037 else if (p->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
1038 c->bandwidth_hz = 8000000;
1039 else
1040 /* Including BANDWIDTH_AUTO */
1041 c->bandwidth_hz = 0;
Steven Tothee33c522008-09-11 23:52:32 -03001042 c->code_rate_HP = p->u.ofdm.code_rate_HP;
1043 c->code_rate_LP = p->u.ofdm.code_rate_LP;
1044 c->modulation = p->u.ofdm.constellation;
1045 c->transmission_mode = p->u.ofdm.transmission_mode;
1046 c->guard_interval = p->u.ofdm.guard_interval;
1047 c->hierarchy = p->u.ofdm.hierarchy_information;
Steven Toth80a773c2008-09-12 00:53:50 -03001048 c->delivery_system = SYS_DVBT;
Steven Tothee33c522008-09-11 23:52:32 -03001049 break;
1050 case FE_ATSC:
1051 c->modulation = p->u.vsb.modulation;
Steven Toth80a773c2008-09-12 00:53:50 -03001052 if ((c->modulation == VSB_8) || (c->modulation == VSB_16))
1053 c->delivery_system = SYS_ATSC;
1054 else
1055 c->delivery_system = SYS_DVBC_ANNEX_B;
Steven Tothee33c522008-09-11 23:52:32 -03001056 break;
1057 }
1058}
1059
Steven Tothd5748f12008-09-12 00:27:13 -03001060/* Ensure the cached values are set correctly in the frontend
1061 * legacy tuning structures, for the advanced tuning API.
1062 */
Mauro Carvalho Chehab072ce0c2009-01-05 01:19:06 -03001063static void dtv_property_legacy_params_sync(struct dvb_frontend *fe)
Steven Toth6b73eea2008-09-04 01:12:25 -03001064{
Steven Toth56f06802008-09-11 10:19:27 -03001065 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
Steven Toth6b73eea2008-09-04 01:12:25 -03001066 struct dvb_frontend_private *fepriv = fe->frontend_priv;
Steven Tothd5748f12008-09-12 00:27:13 -03001067 struct dvb_frontend_parameters *p = &fepriv->parameters;
Steven Toth6b73eea2008-09-04 01:12:25 -03001068
Steven Tothd5748f12008-09-12 00:27:13 -03001069 p->frequency = c->frequency;
1070 p->inversion = c->inversion;
1071
1072 switch (fe->ops.info.type) {
1073 case FE_QPSK:
Steven Totha1bc84c2008-10-17 00:20:19 -03001074 dprintk("%s() Preparing QPSK req\n", __func__);
Steven Tothd5748f12008-09-12 00:27:13 -03001075 p->u.qpsk.symbol_rate = c->symbol_rate;
1076 p->u.qpsk.fec_inner = c->fec_inner;
Steven Toth80a773c2008-09-12 00:53:50 -03001077 c->delivery_system = SYS_DVBS;
Steven Tothd5748f12008-09-12 00:27:13 -03001078 break;
1079 case FE_QAM:
Steven Totha1bc84c2008-10-17 00:20:19 -03001080 dprintk("%s() Preparing QAM req\n", __func__);
Steven Tothd5748f12008-09-12 00:27:13 -03001081 p->u.qam.symbol_rate = c->symbol_rate;
1082 p->u.qam.fec_inner = c->fec_inner;
1083 p->u.qam.modulation = c->modulation;
Steven Toth80a773c2008-09-12 00:53:50 -03001084 c->delivery_system = SYS_DVBC_ANNEX_AC;
Steven Tothd5748f12008-09-12 00:27:13 -03001085 break;
1086 case FE_OFDM:
Steven Totha1bc84c2008-10-17 00:20:19 -03001087 dprintk("%s() Preparing OFDM req\n", __func__);
Steven Toth75b7f942008-09-13 16:56:34 -03001088 if (c->bandwidth_hz == 6000000)
1089 p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;
1090 else if (c->bandwidth_hz == 7000000)
1091 p->u.ofdm.bandwidth = BANDWIDTH_7_MHZ;
1092 else if (c->bandwidth_hz == 8000000)
1093 p->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
1094 else
1095 p->u.ofdm.bandwidth = BANDWIDTH_AUTO;
Steven Tothd5748f12008-09-12 00:27:13 -03001096 p->u.ofdm.code_rate_HP = c->code_rate_HP;
1097 p->u.ofdm.code_rate_LP = c->code_rate_LP;
1098 p->u.ofdm.constellation = c->modulation;
1099 p->u.ofdm.transmission_mode = c->transmission_mode;
1100 p->u.ofdm.guard_interval = c->guard_interval;
1101 p->u.ofdm.hierarchy_information = c->hierarchy;
Steven Toth80a773c2008-09-12 00:53:50 -03001102 c->delivery_system = SYS_DVBT;
Steven Tothd5748f12008-09-12 00:27:13 -03001103 break;
1104 case FE_ATSC:
Steven Totha1bc84c2008-10-17 00:20:19 -03001105 dprintk("%s() Preparing VSB req\n", __func__);
Steven Tothd5748f12008-09-12 00:27:13 -03001106 p->u.vsb.modulation = c->modulation;
Steven Toth80a773c2008-09-12 00:53:50 -03001107 if ((c->modulation == VSB_8) || (c->modulation == VSB_16))
1108 c->delivery_system = SYS_ATSC;
1109 else
1110 c->delivery_system = SYS_DVBC_ANNEX_B;
Steven Tothd5748f12008-09-12 00:27:13 -03001111 break;
1112 }
1113}
1114
1115/* Ensure the cached values are set correctly in the frontend
1116 * legacy tuning structures, for the legacy tuning API.
1117 */
Mauro Carvalho Chehab072ce0c2009-01-05 01:19:06 -03001118static void dtv_property_adv_params_sync(struct dvb_frontend *fe)
Steven Tothd5748f12008-09-12 00:27:13 -03001119{
1120 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
1121 struct dvb_frontend_private *fepriv = fe->frontend_priv;
1122 struct dvb_frontend_parameters *p = &fepriv->parameters;
1123
Steven Tothd5748f12008-09-12 00:27:13 -03001124 p->frequency = c->frequency;
1125 p->inversion = c->inversion;
1126
1127 switch(c->modulation) {
Steven Toth0a6393a2008-10-06 21:06:48 -03001128 case PSK_8:
1129 case APSK_16:
Manu Abraham97854822008-10-14 19:48:07 -03001130 case APSK_32:
Steven Toth0a6393a2008-10-06 21:06:48 -03001131 case QPSK:
Steven Tothd5748f12008-09-12 00:27:13 -03001132 p->u.qpsk.symbol_rate = c->symbol_rate;
1133 p->u.qpsk.fec_inner = c->fec_inner;
1134 break;
1135 default:
1136 break;
1137 }
1138
1139 if(c->delivery_system == SYS_ISDBT) {
1140 /* Fake out a generic DVB-T request so we pass validation in the ioctl */
1141 p->frequency = c->frequency;
1142 p->inversion = INVERSION_AUTO;
1143 p->u.ofdm.constellation = QAM_AUTO;
1144 p->u.ofdm.code_rate_HP = FEC_AUTO;
1145 p->u.ofdm.code_rate_LP = FEC_AUTO;
1146 p->u.ofdm.bandwidth = BANDWIDTH_AUTO;
1147 p->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO;
1148 p->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO;
1149 p->u.ofdm.hierarchy_information = HIERARCHY_AUTO;
1150 }
1151}
1152
Mauro Carvalho Chehab072ce0c2009-01-05 01:19:06 -03001153static void dtv_property_cache_submit(struct dvb_frontend *fe)
Steven Tothd5748f12008-09-12 00:27:13 -03001154{
1155 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
1156
Steven Tothd5748f12008-09-12 00:27:13 -03001157 /* For legacy delivery systems we don't need the delivery_system to
1158 * be specified, but we populate the older structures from the cache
1159 * so we can call set_frontend on older drivers.
1160 */
Steven Toth6b73eea2008-09-04 01:12:25 -03001161 if(is_legacy_delivery_system(c->delivery_system)) {
Steven Tothd5748f12008-09-12 00:27:13 -03001162
Steven Totha1bc84c2008-10-17 00:20:19 -03001163 dprintk("%s() legacy, modulation = %d\n", __func__, c->modulation);
Steven Tothd5748f12008-09-12 00:27:13 -03001164 dtv_property_legacy_params_sync(fe);
Steven Toth6b73eea2008-09-04 01:12:25 -03001165
Steven Toth6b73eea2008-09-04 01:12:25 -03001166 } else {
Steven Totha1bc84c2008-10-17 00:20:19 -03001167 dprintk("%s() adv, modulation = %d\n", __func__, c->modulation);
Steven Tothd5748f12008-09-12 00:27:13 -03001168
Steven Toth6b73eea2008-09-04 01:12:25 -03001169 /* For advanced delivery systems / modulation types ...
1170 * we seed the lecacy dvb_frontend_parameters structure
1171 * so that the sanity checking code later in the IOCTL processing
1172 * can validate our basic frequency ranges, symbolrates, modulation
1173 * etc.
1174 */
Steven Tothd5748f12008-09-12 00:27:13 -03001175 dtv_property_adv_params_sync(fe);
Steven Toth6b73eea2008-09-04 01:12:25 -03001176 }
Steven Toth6b73eea2008-09-04 01:12:25 -03001177}
1178
Steven Toth13c97bf2008-09-04 21:19:43 -03001179static int dvb_frontend_ioctl_legacy(struct inode *inode, struct file *file,
1180 unsigned int cmd, void *parg);
1181static int dvb_frontend_ioctl_properties(struct inode *inode, struct file *file,
1182 unsigned int cmd, void *parg);
1183
Mauro Carvalho Chehab072ce0c2009-01-05 01:19:06 -03001184static int dtv_property_process_get(struct dvb_frontend *fe,
1185 struct dtv_property *tvp,
1186 struct inode *inode, struct file *file)
Steven Toth363429a2008-09-12 01:34:28 -03001187{
1188 int r = 0;
1189
Steven Toth363429a2008-09-12 01:34:28 -03001190 dtv_property_dump(tvp);
1191
Steven Tothbfbf2da2008-09-12 01:37:37 -03001192 /* Allow the frontend to validate incoming properties */
1193 if (fe->ops.get_property)
1194 r = fe->ops.get_property(fe, tvp);
1195
1196 if (r < 0)
1197 return r;
1198
Steven Toth363429a2008-09-12 01:34:28 -03001199 switch(tvp->cmd) {
1200 case DTV_FREQUENCY:
1201 tvp->u.data = fe->dtv_property_cache.frequency;
1202 break;
1203 case DTV_MODULATION:
1204 tvp->u.data = fe->dtv_property_cache.modulation;
1205 break;
Steven Toth75b7f942008-09-13 16:56:34 -03001206 case DTV_BANDWIDTH_HZ:
1207 tvp->u.data = fe->dtv_property_cache.bandwidth_hz;
Steven Toth363429a2008-09-12 01:34:28 -03001208 break;
1209 case DTV_INVERSION:
1210 tvp->u.data = fe->dtv_property_cache.inversion;
1211 break;
1212 case DTV_SYMBOL_RATE:
1213 tvp->u.data = fe->dtv_property_cache.symbol_rate;
1214 break;
1215 case DTV_INNER_FEC:
1216 tvp->u.data = fe->dtv_property_cache.fec_inner;
1217 break;
1218 case DTV_PILOT:
1219 tvp->u.data = fe->dtv_property_cache.pilot;
1220 break;
1221 case DTV_ROLLOFF:
1222 tvp->u.data = fe->dtv_property_cache.rolloff;
1223 break;
1224 case DTV_DELIVERY_SYSTEM:
1225 tvp->u.data = fe->dtv_property_cache.delivery_system;
1226 break;
Steven Toth363429a2008-09-12 01:34:28 -03001227 case DTV_VOLTAGE:
1228 tvp->u.data = fe->dtv_property_cache.voltage;
1229 break;
1230 case DTV_TONE:
1231 tvp->u.data = fe->dtv_property_cache.sectone;
1232 break;
Steven Totheacf8d82008-09-26 00:29:49 -03001233 case DTV_API_VERSION:
1234 tvp->u.data = (DVB_API_VERSION << 8) | DVB_API_VERSION_MINOR;
1235 break;
Steven Totha4de91b2008-10-06 21:55:46 -03001236 case DTV_CODE_RATE_HP:
1237 tvp->u.data = fe->dtv_property_cache.code_rate_HP;
1238 break;
1239 case DTV_CODE_RATE_LP:
1240 tvp->u.data = fe->dtv_property_cache.code_rate_LP;
1241 break;
Steven Tothb87625f2008-10-06 21:56:59 -03001242 case DTV_GUARD_INTERVAL:
1243 tvp->u.data = fe->dtv_property_cache.guard_interval;
1244 break;
1245 case DTV_TRANSMISSION_MODE:
1246 tvp->u.data = fe->dtv_property_cache.transmission_mode;
1247 break;
Steven Tothef526f42008-10-06 22:01:47 -03001248 case DTV_HIERARCHY:
1249 tvp->u.data = fe->dtv_property_cache.hierarchy;
1250 break;
Steven Toth363429a2008-09-12 01:34:28 -03001251 default:
1252 r = -1;
1253 }
1254
1255 return r;
1256}
1257
Mauro Carvalho Chehab072ce0c2009-01-05 01:19:06 -03001258static int dtv_property_process_set(struct dvb_frontend *fe,
1259 struct dtv_property *tvp,
1260 struct inode *inode,
1261 struct file *file)
Steven Toth6b73eea2008-09-04 01:12:25 -03001262{
1263 int r = 0;
Steven Toth13c97bf2008-09-04 21:19:43 -03001264 struct dvb_frontend_private *fepriv = fe->frontend_priv;
Steven Toth56f06802008-09-11 10:19:27 -03001265 dtv_property_dump(tvp);
Steven Toth6b73eea2008-09-04 01:12:25 -03001266
Steven Tothbfbf2da2008-09-12 01:37:37 -03001267 /* Allow the frontend to validate incoming properties */
1268 if (fe->ops.set_property)
1269 r = fe->ops.set_property(fe, tvp);
1270
1271 if (r < 0)
1272 return r;
1273
Steven Toth6b73eea2008-09-04 01:12:25 -03001274 switch(tvp->cmd) {
Steven Tothe7fee0f32008-09-11 10:23:01 -03001275 case DTV_CLEAR:
Steven Toth6b73eea2008-09-04 01:12:25 -03001276 /* Reset a cache of data specific to the frontend here. This does
1277 * not effect hardware.
1278 */
Steven Totha1bc84c2008-10-17 00:20:19 -03001279 dprintk("%s() Flushing property cache\n", __func__);
Steven Toth56f06802008-09-11 10:19:27 -03001280 memset(&fe->dtv_property_cache, 0, sizeof(struct dtv_frontend_properties));
Steven Tothe7fee0f32008-09-11 10:23:01 -03001281 fe->dtv_property_cache.state = tvp->cmd;
Steven Toth56f06802008-09-11 10:19:27 -03001282 fe->dtv_property_cache.delivery_system = SYS_UNDEFINED;
Steven Toth6b73eea2008-09-04 01:12:25 -03001283 break;
Steven Tothe7fee0f32008-09-11 10:23:01 -03001284 case DTV_TUNE:
Steven Toth6b73eea2008-09-04 01:12:25 -03001285 /* interpret the cache of data, build either a traditional frontend
Steven Tothd5748f12008-09-12 00:27:13 -03001286 * tunerequest so we can pass validation in the FE_SET_FRONTEND
1287 * ioctl.
Steven Toth6b73eea2008-09-04 01:12:25 -03001288 */
Steven Tothe7fee0f32008-09-11 10:23:01 -03001289 fe->dtv_property_cache.state = tvp->cmd;
Steven Totha1bc84c2008-10-17 00:20:19 -03001290 dprintk("%s() Finalised property cache\n", __func__);
Steven Tothd5748f12008-09-12 00:27:13 -03001291 dtv_property_cache_submit(fe);
1292
Steven Toth13c97bf2008-09-04 21:19:43 -03001293 r |= dvb_frontend_ioctl_legacy(inode, file, FE_SET_FRONTEND,
1294 &fepriv->parameters);
Steven Toth6b73eea2008-09-04 01:12:25 -03001295 break;
Steven Toth363429a2008-09-12 01:34:28 -03001296 case DTV_FREQUENCY:
Steven Toth56f06802008-09-11 10:19:27 -03001297 fe->dtv_property_cache.frequency = tvp->u.data;
Steven Toth6b73eea2008-09-04 01:12:25 -03001298 break;
Steven Toth363429a2008-09-12 01:34:28 -03001299 case DTV_MODULATION:
Steven Toth56f06802008-09-11 10:19:27 -03001300 fe->dtv_property_cache.modulation = tvp->u.data;
Steven Toth6b73eea2008-09-04 01:12:25 -03001301 break;
Steven Toth75b7f942008-09-13 16:56:34 -03001302 case DTV_BANDWIDTH_HZ:
1303 fe->dtv_property_cache.bandwidth_hz = tvp->u.data;
Steven Toth6b73eea2008-09-04 01:12:25 -03001304 break;
Steven Toth363429a2008-09-12 01:34:28 -03001305 case DTV_INVERSION:
Steven Toth56f06802008-09-11 10:19:27 -03001306 fe->dtv_property_cache.inversion = tvp->u.data;
Steven Toth6b73eea2008-09-04 01:12:25 -03001307 break;
Steven Toth363429a2008-09-12 01:34:28 -03001308 case DTV_SYMBOL_RATE:
Steven Toth56f06802008-09-11 10:19:27 -03001309 fe->dtv_property_cache.symbol_rate = tvp->u.data;
Steven Toth6b73eea2008-09-04 01:12:25 -03001310 break;
Steven Toth363429a2008-09-12 01:34:28 -03001311 case DTV_INNER_FEC:
Steven Toth56f06802008-09-11 10:19:27 -03001312 fe->dtv_property_cache.fec_inner = tvp->u.data;
Steven Toth6b73eea2008-09-04 01:12:25 -03001313 break;
Steven Toth363429a2008-09-12 01:34:28 -03001314 case DTV_PILOT:
Steven Toth56f06802008-09-11 10:19:27 -03001315 fe->dtv_property_cache.pilot = tvp->u.data;
Steven Toth6b73eea2008-09-04 01:12:25 -03001316 break;
Steven Toth363429a2008-09-12 01:34:28 -03001317 case DTV_ROLLOFF:
Steven Toth56f06802008-09-11 10:19:27 -03001318 fe->dtv_property_cache.rolloff = tvp->u.data;
Steven Toth6b73eea2008-09-04 01:12:25 -03001319 break;
Steven Toth363429a2008-09-12 01:34:28 -03001320 case DTV_DELIVERY_SYSTEM:
Steven Toth56f06802008-09-11 10:19:27 -03001321 fe->dtv_property_cache.delivery_system = tvp->u.data;
Steven Toth6b73eea2008-09-04 01:12:25 -03001322 break;
Steven Toth363429a2008-09-12 01:34:28 -03001323 case DTV_VOLTAGE:
Steven Toth56f06802008-09-11 10:19:27 -03001324 fe->dtv_property_cache.voltage = tvp->u.data;
Steven Toth13c97bf2008-09-04 21:19:43 -03001325 r = dvb_frontend_ioctl_legacy(inode, file, FE_SET_VOLTAGE,
Steven Toth56f06802008-09-11 10:19:27 -03001326 (void *)fe->dtv_property_cache.voltage);
Steven Toth13c97bf2008-09-04 21:19:43 -03001327 break;
Steven Toth363429a2008-09-12 01:34:28 -03001328 case DTV_TONE:
Steven Toth56f06802008-09-11 10:19:27 -03001329 fe->dtv_property_cache.sectone = tvp->u.data;
Steven Toth13c97bf2008-09-04 21:19:43 -03001330 r = dvb_frontend_ioctl_legacy(inode, file, FE_SET_TONE,
Steven Toth56f06802008-09-11 10:19:27 -03001331 (void *)fe->dtv_property_cache.sectone);
Steven Toth13c97bf2008-09-04 21:19:43 -03001332 break;
Steven Totha4de91b2008-10-06 21:55:46 -03001333 case DTV_CODE_RATE_HP:
1334 fe->dtv_property_cache.code_rate_HP = tvp->u.data;
1335 break;
1336 case DTV_CODE_RATE_LP:
1337 fe->dtv_property_cache.code_rate_LP = tvp->u.data;
1338 break;
Steven Tothb87625f2008-10-06 21:56:59 -03001339 case DTV_GUARD_INTERVAL:
1340 fe->dtv_property_cache.guard_interval = tvp->u.data;
1341 break;
1342 case DTV_TRANSMISSION_MODE:
1343 fe->dtv_property_cache.transmission_mode = tvp->u.data;
1344 break;
Steven Tothef526f42008-10-06 22:01:47 -03001345 case DTV_HIERARCHY:
1346 fe->dtv_property_cache.hierarchy = tvp->u.data;
1347 break;
Steven Toth363429a2008-09-12 01:34:28 -03001348 default:
1349 r = -1;
Steven Toth6b73eea2008-09-04 01:12:25 -03001350 }
1351
Steven Toth13c97bf2008-09-04 21:19:43 -03001352 return r;
Steven Toth6b73eea2008-09-04 01:12:25 -03001353}
1354
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
1356 unsigned int cmd, void *parg)
1357{
1358 struct dvb_device *dvbdev = file->private_data;
1359 struct dvb_frontend *fe = dvbdev->priv;
Johannes Stezenbach0c53c702005-05-16 21:54:24 -07001360 struct dvb_frontend_private *fepriv = fe->frontend_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361 int err = -EOPNOTSUPP;
1362
Harvey Harrison46b4f7c2008-04-08 23:20:00 -03001363 dprintk ("%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364
Adrian Bunk813ce472007-08-01 10:13:36 -03001365 if (fepriv->exit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366 return -ENODEV;
1367
1368 if ((file->f_flags & O_ACCMODE) == O_RDONLY &&
1369 (_IOC_DIR(cmd) != _IOC_READ || cmd == FE_GET_EVENT ||
1370 cmd == FE_DISEQC_RECV_SLAVE_REPLY))
1371 return -EPERM;
1372
1373 if (down_interruptible (&fepriv->sem))
1374 return -ERESTARTSYS;
1375
Steven Toth13c97bf2008-09-04 21:19:43 -03001376 if ((cmd == FE_SET_PROPERTY) || (cmd == FE_GET_PROPERTY))
1377 err = dvb_frontend_ioctl_properties(inode, file, cmd, parg);
Steven Toth4dd88be2008-09-13 15:09:07 -03001378 else {
1379 fe->dtv_property_cache.state = DTV_UNDEFINED;
Steven Toth13c97bf2008-09-04 21:19:43 -03001380 err = dvb_frontend_ioctl_legacy(inode, file, cmd, parg);
Steven Toth4dd88be2008-09-13 15:09:07 -03001381 }
Steven Toth13c97bf2008-09-04 21:19:43 -03001382
1383 up(&fepriv->sem);
1384 return err;
1385}
1386
1387static int dvb_frontend_ioctl_properties(struct inode *inode, struct file *file,
1388 unsigned int cmd, void *parg)
1389{
1390 struct dvb_device *dvbdev = file->private_data;
1391 struct dvb_frontend *fe = dvbdev->priv;
Igor M. Liplianine6f9ec82008-09-12 14:49:06 -03001392 int err = 0;
Steven Tothe7fee0f32008-09-11 10:23:01 -03001393
1394 struct dtv_properties *tvps = NULL;
1395 struct dtv_property *tvp = NULL;
1396 int i;
Steven Toth13c97bf2008-09-04 21:19:43 -03001397
1398 dprintk("%s\n", __func__);
1399
Steven Toth6b73eea2008-09-04 01:12:25 -03001400 if(cmd == FE_SET_PROPERTY) {
Steven Tothe7fee0f32008-09-11 10:23:01 -03001401 tvps = (struct dtv_properties __user *)parg;
Steven Toth6b73eea2008-09-04 01:12:25 -03001402
Steven Totha1bc84c2008-10-17 00:20:19 -03001403 dprintk("%s() properties.num = %d\n", __func__, tvps->num);
1404 dprintk("%s() properties.props = %p\n", __func__, tvps->props);
Steven Tothe7fee0f32008-09-11 10:23:01 -03001405
1406 /* Put an arbitrary limit on the number of messages that can
1407 * be sent at once */
Steven Toth6068f502008-10-06 22:46:08 -03001408 if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS))
Steven Tothe7fee0f32008-09-11 10:23:01 -03001409 return -EINVAL;
1410
1411 tvp = (struct dtv_property *) kmalloc(tvps->num *
1412 sizeof(struct dtv_property), GFP_KERNEL);
1413 if (!tvp) {
1414 err = -ENOMEM;
1415 goto out;
Steven Toth6b73eea2008-09-04 01:12:25 -03001416 }
1417
Steven Tothe7fee0f32008-09-11 10:23:01 -03001418 if (copy_from_user(tvp, tvps->props, tvps->num * sizeof(struct dtv_property))) {
1419 err = -EFAULT;
1420 goto out;
1421 }
1422
Steven Tothd48cb402008-09-26 00:16:25 -03001423 for (i = 0; i < tvps->num; i++) {
1424 (tvp + i)->result = dtv_property_process_set(fe, tvp + i, inode, file);
1425 err |= (tvp + i)->result;
1426 }
Steven Tothe7fee0f32008-09-11 10:23:01 -03001427
Steven Totha1bc84c2008-10-17 00:20:19 -03001428 if(fe->dtv_property_cache.state == DTV_TUNE)
1429 dprintk("%s() Property cache is full, tuning\n", __func__);
Steven Tothbfbf2da2008-09-12 01:37:37 -03001430
Steven Toth363429a2008-09-12 01:34:28 -03001431 } else
1432 if(cmd == FE_GET_PROPERTY) {
Steven Toth363429a2008-09-12 01:34:28 -03001433
1434 tvps = (struct dtv_properties __user *)parg;
1435
Steven Totha1bc84c2008-10-17 00:20:19 -03001436 dprintk("%s() properties.num = %d\n", __func__, tvps->num);
1437 dprintk("%s() properties.props = %p\n", __func__, tvps->props);
Steven Toth363429a2008-09-12 01:34:28 -03001438
1439 /* Put an arbitrary limit on the number of messages that can
1440 * be sent at once */
Steven Toth6068f502008-10-06 22:46:08 -03001441 if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS))
Steven Toth363429a2008-09-12 01:34:28 -03001442 return -EINVAL;
1443
1444 tvp = (struct dtv_property *) kmalloc(tvps->num *
1445 sizeof(struct dtv_property), GFP_KERNEL);
1446 if (!tvp) {
1447 err = -ENOMEM;
1448 goto out;
1449 }
1450
1451 if (copy_from_user(tvp, tvps->props, tvps->num * sizeof(struct dtv_property))) {
1452 err = -EFAULT;
1453 goto out;
1454 }
1455
Steven Tothd48cb402008-09-26 00:16:25 -03001456 for (i = 0; i < tvps->num; i++) {
1457 (tvp + i)->result = dtv_property_process_get(fe, tvp + i, inode, file);
1458 err |= (tvp + i)->result;
1459 }
Steven Toth363429a2008-09-12 01:34:28 -03001460
1461 if (copy_to_user(tvps->props, tvp, tvps->num * sizeof(struct dtv_property))) {
1462 err = -EFAULT;
1463 goto out;
1464 }
1465
Steven Toth363429a2008-09-12 01:34:28 -03001466 } else
1467 err = -EOPNOTSUPP;
1468
Steven Tothe7fee0f32008-09-11 10:23:01 -03001469out:
1470 kfree(tvp);
Steven Toth13c97bf2008-09-04 21:19:43 -03001471 return err;
1472}
1473
1474static int dvb_frontend_ioctl_legacy(struct inode *inode, struct file *file,
1475 unsigned int cmd, void *parg)
1476{
1477 struct dvb_device *dvbdev = file->private_data;
1478 struct dvb_frontend *fe = dvbdev->priv;
1479 struct dvb_frontend_private *fepriv = fe->frontend_priv;
1480 int err = -EOPNOTSUPP;
1481
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 switch (cmd) {
1483 case FE_GET_INFO: {
Johannes Stezenbach0c53c702005-05-16 21:54:24 -07001484 struct dvb_frontend_info* info = parg;
Patrick Boettcherdea74862006-05-14 05:01:31 -03001485 memcpy(info, &fe->ops.info, sizeof(struct dvb_frontend_info));
Oliver Endrissc471b332007-08-09 01:03:42 -03001486 dvb_frontend_get_frequeny_limits(fe, &info->frequency_min, &info->frequency_max);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487
1488 /* Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't
1489 * do it, it is done for it. */
1490 info->caps |= FE_CAN_INVERSION_AUTO;
1491 err = 0;
1492 break;
1493 }
1494
Peter Beutner6757ccc2005-07-07 17:57:36 -07001495 case FE_READ_STATUS: {
1496 fe_status_t* status = parg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497
Peter Beutner6757ccc2005-07-07 17:57:36 -07001498 /* if retune was requested but hasn't occured yet, prevent
1499 * that user get signal state from previous tuning */
1500 if(fepriv->state == FESTATE_RETUNE) {
1501 err=0;
1502 *status = 0;
1503 break;
1504 }
1505
Patrick Boettcherdea74862006-05-14 05:01:31 -03001506 if (fe->ops.read_status)
1507 err = fe->ops.read_status(fe, status);
Peter Beutner6757ccc2005-07-07 17:57:36 -07001508 break;
1509 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510 case FE_READ_BER:
Patrick Boettcherdea74862006-05-14 05:01:31 -03001511 if (fe->ops.read_ber)
1512 err = fe->ops.read_ber(fe, (__u32*) parg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513 break;
1514
1515 case FE_READ_SIGNAL_STRENGTH:
Patrick Boettcherdea74862006-05-14 05:01:31 -03001516 if (fe->ops.read_signal_strength)
1517 err = fe->ops.read_signal_strength(fe, (__u16*) parg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518 break;
1519
1520 case FE_READ_SNR:
Patrick Boettcherdea74862006-05-14 05:01:31 -03001521 if (fe->ops.read_snr)
1522 err = fe->ops.read_snr(fe, (__u16*) parg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523 break;
1524
1525 case FE_READ_UNCORRECTED_BLOCKS:
Patrick Boettcherdea74862006-05-14 05:01:31 -03001526 if (fe->ops.read_ucblocks)
1527 err = fe->ops.read_ucblocks(fe, (__u32*) parg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528 break;
1529
1530
1531 case FE_DISEQC_RESET_OVERLOAD:
Patrick Boettcherdea74862006-05-14 05:01:31 -03001532 if (fe->ops.diseqc_reset_overload) {
1533 err = fe->ops.diseqc_reset_overload(fe);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534 fepriv->state = FESTATE_DISEQC;
1535 fepriv->status = 0;
1536 }
1537 break;
1538
1539 case FE_DISEQC_SEND_MASTER_CMD:
Patrick Boettcherdea74862006-05-14 05:01:31 -03001540 if (fe->ops.diseqc_send_master_cmd) {
1541 err = fe->ops.diseqc_send_master_cmd(fe, (struct dvb_diseqc_master_cmd*) parg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542 fepriv->state = FESTATE_DISEQC;
1543 fepriv->status = 0;
1544 }
1545 break;
1546
1547 case FE_DISEQC_SEND_BURST:
Patrick Boettcherdea74862006-05-14 05:01:31 -03001548 if (fe->ops.diseqc_send_burst) {
1549 err = fe->ops.diseqc_send_burst(fe, (fe_sec_mini_cmd_t) parg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 fepriv->state = FESTATE_DISEQC;
1551 fepriv->status = 0;
1552 }
1553 break;
1554
1555 case FE_SET_TONE:
Patrick Boettcherdea74862006-05-14 05:01:31 -03001556 if (fe->ops.set_tone) {
1557 err = fe->ops.set_tone(fe, (fe_sec_tone_mode_t) parg);
Andrew de Quincey64454012006-04-06 14:32:23 -03001558 fepriv->tone = (fe_sec_tone_mode_t) parg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559 fepriv->state = FESTATE_DISEQC;
1560 fepriv->status = 0;
1561 }
1562 break;
1563
1564 case FE_SET_VOLTAGE:
Patrick Boettcherdea74862006-05-14 05:01:31 -03001565 if (fe->ops.set_voltage) {
1566 err = fe->ops.set_voltage(fe, (fe_sec_voltage_t) parg);
Andrew de Quincey64454012006-04-06 14:32:23 -03001567 fepriv->voltage = (fe_sec_voltage_t) parg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568 fepriv->state = FESTATE_DISEQC;
1569 fepriv->status = 0;
1570 }
1571 break;
1572
1573 case FE_DISHNETWORK_SEND_LEGACY_CMD:
Patrick Boettcherdea74862006-05-14 05:01:31 -03001574 if (fe->ops.dishnetwork_send_legacy_command) {
1575 err = fe->ops.dishnetwork_send_legacy_command(fe, (unsigned long) parg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576 fepriv->state = FESTATE_DISEQC;
1577 fepriv->status = 0;
Patrick Boettcherdea74862006-05-14 05:01:31 -03001578 } else if (fe->ops.set_voltage) {
NooneImportant83b75b02005-11-08 21:35:27 -08001579 /*
1580 * NOTE: This is a fallback condition. Some frontends
1581 * (stv0299 for instance) take longer than 8msec to
1582 * respond to a set_voltage command. Those switches
1583 * need custom routines to switch properly. For all
1584 * other frontends, the following shoule work ok.
1585 * Dish network legacy switches (as used by Dish500)
1586 * are controlled by sending 9-bit command words
1587 * spaced 8msec apart.
1588 * the actual command word is switch/port dependant
1589 * so it is up to the userspace application to send
1590 * the right command.
1591 * The command must always start with a '0' after
1592 * initialization, so parg is 8 bits and does not
1593 * include the initialization or start bit
1594 */
Hans Verkuilc6eb8ea2008-09-03 17:11:54 -03001595 unsigned long swcmd = ((unsigned long) parg) << 1;
NooneImportant83b75b02005-11-08 21:35:27 -08001596 struct timeval nexttime;
1597 struct timeval tv[10];
1598 int i;
1599 u8 last = 1;
1600 if (dvb_frontend_debug)
Hans Verkuilc6eb8ea2008-09-03 17:11:54 -03001601 printk("%s switch command: 0x%04lx\n", __func__, swcmd);
NooneImportant83b75b02005-11-08 21:35:27 -08001602 do_gettimeofday(&nexttime);
1603 if (dvb_frontend_debug)
1604 memcpy(&tv[0], &nexttime, sizeof(struct timeval));
1605 /* before sending a command, initialize by sending
1606 * a 32ms 18V to the switch
1607 */
Patrick Boettcherdea74862006-05-14 05:01:31 -03001608 fe->ops.set_voltage(fe, SEC_VOLTAGE_18);
NooneImportant83b75b02005-11-08 21:35:27 -08001609 dvb_frontend_sleep_until(&nexttime, 32000);
1610
1611 for (i = 0; i < 9; i++) {
1612 if (dvb_frontend_debug)
1613 do_gettimeofday(&tv[i + 1]);
Hans Verkuilc6eb8ea2008-09-03 17:11:54 -03001614 if ((swcmd & 0x01) != last) {
NooneImportant83b75b02005-11-08 21:35:27 -08001615 /* set voltage to (last ? 13V : 18V) */
Patrick Boettcherdea74862006-05-14 05:01:31 -03001616 fe->ops.set_voltage(fe, (last) ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18);
NooneImportant83b75b02005-11-08 21:35:27 -08001617 last = (last) ? 0 : 1;
1618 }
Hans Verkuilc6eb8ea2008-09-03 17:11:54 -03001619 swcmd = swcmd >> 1;
NooneImportant83b75b02005-11-08 21:35:27 -08001620 if (i != 8)
1621 dvb_frontend_sleep_until(&nexttime, 8000);
1622 }
1623 if (dvb_frontend_debug) {
1624 printk("%s(%d): switch delay (should be 32k followed by all 8k\n",
Harvey Harrison46b4f7c2008-04-08 23:20:00 -03001625 __func__, fe->dvb->num);
NooneImportant83b75b02005-11-08 21:35:27 -08001626 for (i = 1; i < 10; i++)
1627 printk("%d: %d\n", i, timeval_usec_diff(tv[i-1] , tv[i]));
1628 }
1629 err = 0;
1630 fepriv->state = FESTATE_DISEQC;
1631 fepriv->status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632 }
1633 break;
1634
1635 case FE_DISEQC_RECV_SLAVE_REPLY:
Patrick Boettcherdea74862006-05-14 05:01:31 -03001636 if (fe->ops.diseqc_recv_slave_reply)
1637 err = fe->ops.diseqc_recv_slave_reply(fe, (struct dvb_diseqc_slave_reply*) parg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638 break;
1639
1640 case FE_ENABLE_HIGH_LNB_VOLTAGE:
Patrick Boettcherdea74862006-05-14 05:01:31 -03001641 if (fe->ops.enable_high_lnb_voltage)
1642 err = fe->ops.enable_high_lnb_voltage(fe, (long) parg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643 break;
1644
1645 case FE_SET_FRONTEND: {
1646 struct dvb_frontend_tune_settings fetunesettings;
1647
Steven Tothe7fee0f32008-09-11 10:23:01 -03001648 if(fe->dtv_property_cache.state == DTV_TUNE) {
Steven Toth6b73eea2008-09-04 01:12:25 -03001649 if (dvb_frontend_check_parameters(fe, &fepriv->parameters) < 0) {
1650 err = -EINVAL;
1651 break;
1652 }
1653 } else {
1654 if (dvb_frontend_check_parameters(fe, parg) < 0) {
1655 err = -EINVAL;
1656 break;
1657 }
Oliver Endriss1fab46f2007-07-23 21:00:36 -03001658
Steven Toth6b73eea2008-09-04 01:12:25 -03001659 memcpy (&fepriv->parameters, parg,
1660 sizeof (struct dvb_frontend_parameters));
Steven Toth1d78cac2008-09-13 18:15:17 -03001661 dtv_property_cache_sync(fe, &fepriv->parameters);
Steven Toth6b73eea2008-09-04 01:12:25 -03001662 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663
1664 memset(&fetunesettings, 0, sizeof(struct dvb_frontend_tune_settings));
1665 memcpy(&fetunesettings.parameters, parg,
1666 sizeof (struct dvb_frontend_parameters));
1667
1668 /* force auto frequency inversion if requested */
1669 if (dvb_force_auto_inversion) {
1670 fepriv->parameters.inversion = INVERSION_AUTO;
1671 fetunesettings.parameters.inversion = INVERSION_AUTO;
1672 }
Patrick Boettcherdea74862006-05-14 05:01:31 -03001673 if (fe->ops.info.type == FE_OFDM) {
Uwe Kleine-König1b3c3712007-02-17 19:23:03 +01001674 /* without hierarchical coding code_rate_LP is irrelevant,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675 * so we tolerate the otherwise invalid FEC_NONE setting */
1676 if (fepriv->parameters.u.ofdm.hierarchy_information == HIERARCHY_NONE &&
1677 fepriv->parameters.u.ofdm.code_rate_LP == FEC_NONE)
1678 fepriv->parameters.u.ofdm.code_rate_LP = FEC_AUTO;
1679 }
1680
1681 /* get frontend-specific tuning settings */
Patrick Boettcherdea74862006-05-14 05:01:31 -03001682 if (fe->ops.get_tune_settings && (fe->ops.get_tune_settings(fe, &fetunesettings) == 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683 fepriv->min_delay = (fetunesettings.min_delay_ms * HZ) / 1000;
1684 fepriv->max_drift = fetunesettings.max_drift;
1685 fepriv->step_size = fetunesettings.step_size;
1686 } else {
1687 /* default values */
Patrick Boettcherdea74862006-05-14 05:01:31 -03001688 switch(fe->ops.info.type) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689 case FE_QPSK:
1690 fepriv->min_delay = HZ/20;
1691 fepriv->step_size = fepriv->parameters.u.qpsk.symbol_rate / 16000;
1692 fepriv->max_drift = fepriv->parameters.u.qpsk.symbol_rate / 2000;
1693 break;
1694
1695 case FE_QAM:
1696 fepriv->min_delay = HZ/20;
1697 fepriv->step_size = 0; /* no zigzag */
1698 fepriv->max_drift = 0;
1699 break;
1700
1701 case FE_OFDM:
1702 fepriv->min_delay = HZ/20;
Patrick Boettcherdea74862006-05-14 05:01:31 -03001703 fepriv->step_size = fe->ops.info.frequency_stepsize * 2;
1704 fepriv->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 break;
1706 case FE_ATSC:
Manu Abraham4821fb12006-06-21 10:27:00 -03001707 fepriv->min_delay = HZ/20;
1708 fepriv->step_size = 0;
1709 fepriv->max_drift = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710 break;
1711 }
1712 }
1713 if (dvb_override_tune_delay > 0)
1714 fepriv->min_delay = (dvb_override_tune_delay * HZ) / 1000;
1715
1716 fepriv->state = FESTATE_RETUNE;
Igor M. Liplianin1d060592008-11-09 11:35:13 -03001717
1718 /* Request the search algorithm to search */
1719 fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;
1720
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721 dvb_frontend_wakeup(fe);
1722 dvb_frontend_add_event(fe, 0);
1723 fepriv->status = 0;
1724 err = 0;
1725 break;
1726 }
1727
1728 case FE_GET_EVENT:
1729 err = dvb_frontend_get_event (fe, parg, file->f_flags);
1730 break;
1731
1732 case FE_GET_FRONTEND:
Patrick Boettcherdea74862006-05-14 05:01:31 -03001733 if (fe->ops.get_frontend) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734 memcpy (parg, &fepriv->parameters, sizeof (struct dvb_frontend_parameters));
Patrick Boettcherdea74862006-05-14 05:01:31 -03001735 err = fe->ops.get_frontend(fe, (struct dvb_frontend_parameters*) parg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 }
1737 break;
Andrew de Quincey36cb5572006-01-09 15:25:07 -02001738
1739 case FE_SET_FRONTEND_TUNE_MODE:
Hans Verkuile18828e2006-01-09 15:25:28 -02001740 fepriv->tune_mode_flags = (unsigned long) parg;
Trent Piepho1b172e02006-06-29 13:16:04 -03001741 err = 0;
Andrew de Quincey36cb5572006-01-09 15:25:07 -02001742 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743 };
1744
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745 return err;
1746}
1747
Steven Toth6b73eea2008-09-04 01:12:25 -03001748
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749static unsigned int dvb_frontend_poll(struct file *file, struct poll_table_struct *wait)
1750{
1751 struct dvb_device *dvbdev = file->private_data;
1752 struct dvb_frontend *fe = dvbdev->priv;
Johannes Stezenbach0c53c702005-05-16 21:54:24 -07001753 struct dvb_frontend_private *fepriv = fe->frontend_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754
Harvey Harrison46b4f7c2008-04-08 23:20:00 -03001755 dprintk ("%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756
1757 poll_wait (file, &fepriv->events.wait_queue, wait);
1758
1759 if (fepriv->events.eventw != fepriv->events.eventr)
1760 return (POLLIN | POLLRDNORM | POLLPRI);
1761
1762 return 0;
1763}
1764
1765static int dvb_frontend_open(struct inode *inode, struct file *file)
1766{
1767 struct dvb_device *dvbdev = file->private_data;
1768 struct dvb_frontend *fe = dvbdev->priv;
Johannes Stezenbach0c53c702005-05-16 21:54:24 -07001769 struct dvb_frontend_private *fepriv = fe->frontend_priv;
Darron Broad59b18422008-10-11 11:44:05 -03001770 struct dvb_adapter *adapter = fe->dvb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771 int ret;
1772
Harvey Harrison46b4f7c2008-04-08 23:20:00 -03001773 dprintk ("%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774
Darron Broad59b18422008-10-11 11:44:05 -03001775 if (adapter->mfe_shared) {
1776 mutex_lock (&adapter->mfe_lock);
Darron Broad65946902008-10-15 13:37:59 -03001777
1778 if (adapter->mfe_dvbdev == NULL)
1779 adapter->mfe_dvbdev = dvbdev;
1780
1781 else if (adapter->mfe_dvbdev != dvbdev) {
1782 struct dvb_device
1783 *mfedev = adapter->mfe_dvbdev;
1784 struct dvb_frontend
1785 *mfe = mfedev->priv;
1786 struct dvb_frontend_private
1787 *mfepriv = mfe->frontend_priv;
1788 int mferetry = (dvb_mfe_wait_time << 1);
1789
1790 mutex_unlock (&adapter->mfe_lock);
1791 while (mferetry-- && (mfedev->users != -1 ||
1792 mfepriv->thread != NULL)) {
1793 if(msleep_interruptible(500)) {
1794 if(signal_pending(current))
1795 return -EINTR;
Darron Broad59b18422008-10-11 11:44:05 -03001796 }
1797 }
Darron Broad65946902008-10-15 13:37:59 -03001798
1799 mutex_lock (&adapter->mfe_lock);
1800 if(adapter->mfe_dvbdev != dvbdev) {
1801 mfedev = adapter->mfe_dvbdev;
1802 mfe = mfedev->priv;
1803 mfepriv = mfe->frontend_priv;
1804 if (mfedev->users != -1 ||
1805 mfepriv->thread != NULL) {
1806 mutex_unlock (&adapter->mfe_lock);
1807 return -EBUSY;
1808 }
1809 adapter->mfe_dvbdev = dvbdev;
1810 }
Darron Broad59b18422008-10-11 11:44:05 -03001811 }
1812 }
1813
Oliver Endriss48136e12007-08-25 12:00:23 -03001814 if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl) {
1815 if ((ret = fe->ops.ts_bus_ctrl(fe, 1)) < 0)
Darron Broad59b18422008-10-11 11:44:05 -03001816 goto err0;
Steven Tothba7e6f32006-09-25 12:41:53 -03001817 }
1818
Oliver Endriss48136e12007-08-25 12:00:23 -03001819 if ((ret = dvb_generic_open (inode, file)) < 0)
1820 goto err1;
Andrew de Quincey04c56d02006-07-10 03:34:14 -03001821
Oliver Endriss48136e12007-08-25 12:00:23 -03001822 if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
Andrew de Quincey04c56d02006-07-10 03:34:14 -03001823 /* normal tune mode when opened R/W */
1824 fepriv->tune_mode_flags &= ~FE_TUNE_MODE_ONESHOT;
1825 fepriv->tone = -1;
1826 fepriv->voltage = -1;
1827
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828 ret = dvb_frontend_start (fe);
1829 if (ret)
Oliver Endriss48136e12007-08-25 12:00:23 -03001830 goto err2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831
1832 /* empty event queue */
1833 fepriv->events.eventr = fepriv->events.eventw = 0;
1834 }
1835
Darron Broad59b18422008-10-11 11:44:05 -03001836 if (adapter->mfe_shared)
1837 mutex_unlock (&adapter->mfe_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838 return ret;
Oliver Endriss48136e12007-08-25 12:00:23 -03001839
1840err2:
1841 dvb_generic_release(inode, file);
1842err1:
1843 if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl)
1844 fe->ops.ts_bus_ctrl(fe, 0);
Darron Broad59b18422008-10-11 11:44:05 -03001845err0:
1846 if (adapter->mfe_shared)
1847 mutex_unlock (&adapter->mfe_lock);
Oliver Endriss48136e12007-08-25 12:00:23 -03001848 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849}
1850
1851static int dvb_frontend_release(struct inode *inode, struct file *file)
1852{
1853 struct dvb_device *dvbdev = file->private_data;
1854 struct dvb_frontend *fe = dvbdev->priv;
Johannes Stezenbach0c53c702005-05-16 21:54:24 -07001855 struct dvb_frontend_private *fepriv = fe->frontend_priv;
Markus Rechbergerca5be9c2007-04-14 10:18:58 -03001856 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857
Harvey Harrison46b4f7c2008-04-08 23:20:00 -03001858 dprintk ("%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859
1860 if ((file->f_flags & O_ACCMODE) != O_RDONLY)
1861 fepriv->release_jiffies = jiffies;
1862
Markus Rechbergerca5be9c2007-04-14 10:18:58 -03001863 ret = dvb_generic_release (inode, file);
1864
Oliver Endriss48136e12007-08-25 12:00:23 -03001865 if (dvbdev->users == -1) {
1866 if (fepriv->exit == 1) {
1867 fops_put(file->f_op);
1868 file->f_op = NULL;
1869 wake_up(&dvbdev->wait_queue);
1870 }
1871 if (fe->ops.ts_bus_ctrl)
1872 fe->ops.ts_bus_ctrl(fe, 0);
Markus Rechbergerca5be9c2007-04-14 10:18:58 -03001873 }
Oliver Endriss48136e12007-08-25 12:00:23 -03001874
Markus Rechbergerca5be9c2007-04-14 10:18:58 -03001875 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876}
1877
Jan Engelhardt784e29d2009-01-11 06:12:43 -03001878static const struct file_operations dvb_frontend_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879 .owner = THIS_MODULE,
1880 .ioctl = dvb_generic_ioctl,
1881 .poll = dvb_frontend_poll,
1882 .open = dvb_frontend_open,
1883 .release = dvb_frontend_release
1884};
1885
1886int dvb_register_frontend(struct dvb_adapter* dvb,
1887 struct dvb_frontend* fe)
1888{
1889 struct dvb_frontend_private *fepriv;
1890 static const struct dvb_device dvbdev_template = {
1891 .users = ~0,
1892 .writers = 1,
1893 .readers = (~0)-1,
1894 .fops = &dvb_frontend_fops,
1895 .kernel_ioctl = dvb_frontend_ioctl
1896 };
1897
Harvey Harrison46b4f7c2008-04-08 23:20:00 -03001898 dprintk ("%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899
Ingo Molnar3593cab2006-02-07 06:49:14 -02001900 if (mutex_lock_interruptible(&frontend_mutex))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901 return -ERESTARTSYS;
1902
Panagiotis Issaris74081872006-01-11 19:40:56 -02001903 fe->frontend_priv = kzalloc(sizeof(struct dvb_frontend_private), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904 if (fe->frontend_priv == NULL) {
Ingo Molnar3593cab2006-02-07 06:49:14 -02001905 mutex_unlock(&frontend_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906 return -ENOMEM;
1907 }
Johannes Stezenbach0c53c702005-05-16 21:54:24 -07001908 fepriv = fe->frontend_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909
1910 init_MUTEX (&fepriv->sem);
1911 init_waitqueue_head (&fepriv->wait_queue);
1912 init_waitqueue_head (&fepriv->events.wait_queue);
Matthias Kaehlcke03b76122007-07-30 14:58:10 -03001913 mutex_init(&fepriv->events.mtx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914 fe->dvb = dvb;
1915 fepriv->inversion = INVERSION_OFF;
1916
Steven Toth363c35f2008-10-11 11:05:50 -03001917 printk ("DVB: registering adapter %i frontend %i (%s)...\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918 fe->dvb->num,
Steven Toth363c35f2008-10-11 11:05:50 -03001919 fe->id,
Patrick Boettcherdea74862006-05-14 05:01:31 -03001920 fe->ops.info.name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921
1922 dvb_register_device (fe->dvb, &fepriv->dvbdev, &dvbdev_template,
1923 fe, DVB_DEVICE_FRONTEND);
1924
Ingo Molnar3593cab2006-02-07 06:49:14 -02001925 mutex_unlock(&frontend_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926 return 0;
1927}
1928EXPORT_SYMBOL(dvb_register_frontend);
1929
1930int dvb_unregister_frontend(struct dvb_frontend* fe)
1931{
Johannes Stezenbach0c53c702005-05-16 21:54:24 -07001932 struct dvb_frontend_private *fepriv = fe->frontend_priv;
Harvey Harrison46b4f7c2008-04-08 23:20:00 -03001933 dprintk ("%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934
Markus Rechberger57861b42007-04-14 10:19:18 -03001935 mutex_lock(&frontend_mutex);
Markus Rechbergerca5be9c2007-04-14 10:18:58 -03001936 dvb_frontend_stop (fe);
Markus Rechberger57861b42007-04-14 10:19:18 -03001937 mutex_unlock(&frontend_mutex);
1938
1939 if (fepriv->dvbdev->users < -1)
1940 wait_event(fepriv->dvbdev->wait_queue,
1941 fepriv->dvbdev->users==-1);
1942
Ingo Molnar3593cab2006-02-07 06:49:14 -02001943 mutex_lock(&frontend_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944 dvb_unregister_device (fepriv->dvbdev);
Andrew de Quinceyd9955062006-08-08 09:10:08 -03001945
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946 /* fe is invalid now */
1947 kfree(fepriv);
Ingo Molnar3593cab2006-02-07 06:49:14 -02001948 mutex_unlock(&frontend_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 return 0;
1950}
1951EXPORT_SYMBOL(dvb_unregister_frontend);
Andrew de Quinceyf52a8382006-08-08 09:10:09 -03001952
Mauro Carvalho Chehab149ef722008-04-29 21:38:46 -03001953#ifdef CONFIG_MEDIA_ATTACH
Andrew de Quinceyf52a8382006-08-08 09:10:09 -03001954void dvb_frontend_detach(struct dvb_frontend* fe)
1955{
1956 void *ptr;
1957
1958 if (fe->ops.release_sec) {
1959 fe->ops.release_sec(fe);
1960 symbol_put_addr(fe->ops.release_sec);
1961 }
1962 if (fe->ops.tuner_ops.release) {
1963 fe->ops.tuner_ops.release(fe);
1964 symbol_put_addr(fe->ops.tuner_ops.release);
1965 }
Michael Krufky2426a272007-12-21 11:34:45 -03001966 if (fe->ops.analog_ops.release) {
1967 fe->ops.analog_ops.release(fe);
1968 symbol_put_addr(fe->ops.analog_ops.release);
1969 }
Andrew de Quinceyf52a8382006-08-08 09:10:09 -03001970 ptr = (void*)fe->ops.release;
1971 if (ptr) {
1972 fe->ops.release(fe);
1973 symbol_put_addr(ptr);
1974 }
1975}
1976#else
1977void dvb_frontend_detach(struct dvb_frontend* fe)
1978{
1979 if (fe->ops.release_sec)
1980 fe->ops.release_sec(fe);
1981 if (fe->ops.tuner_ops.release)
1982 fe->ops.tuner_ops.release(fe);
Michael Krufky2426a272007-12-21 11:34:45 -03001983 if (fe->ops.analog_ops.release)
1984 fe->ops.analog_ops.release(fe);
Andrew de Quinceyf52a8382006-08-08 09:10:09 -03001985 if (fe->ops.release)
1986 fe->ops.release(fe);
1987}
1988#endif
1989EXPORT_SYMBOL(dvb_frontend_detach);