[media] drx-j: Don't use CamelCase
[cascardo/linux.git] / drivers / media / dvb-frontends / drx39xyj / drx_driver.c
1 /*
2   Copyright (c), 2004-2005,2007-2010 Trident Microsystems, Inc.
3   All rights reserved.
4
5   Redistribution and use in source and binary forms, with or without
6   modification, are permitted provided that the following conditions are met:
7
8   * Redistributions of source code must retain the above copyright notice,
9     this list of conditions and the following disclaimer.
10   * Redistributions in binary form must reproduce the above copyright notice,
11     this list of conditions and the following disclaimer in the documentation
12         and/or other materials provided with the distribution.
13   * Neither the name of Trident Microsystems nor Hauppauge Computer Works
14     nor the names of its contributors may be used to endorse or promote
15         products derived from this software without specific prior written
16         permission.
17
18   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28   POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 /**
32 * \file $Id: drx_driver.c,v 1.40 2010/01/12 01:24:56 lfeng Exp $
33 *
34 * \brief Generic DRX functionality, DRX driver core.
35 *
36 */
37
38 /*------------------------------------------------------------------------------
39 INCLUDE FILES
40 ------------------------------------------------------------------------------*/
41 #include "drx_driver.h"
42
43 #define VERSION_FIXED 0
44 #if     VERSION_FIXED
45 #define VERSION_MAJOR 0
46 #define VERSION_MINOR 0
47 #define VERSION_PATCH 0
48 #else
49 #include "drx_driver_version.h"
50 #endif
51
52 /*------------------------------------------------------------------------------
53 DEFINES
54 ------------------------------------------------------------------------------*/
55
56 /*============================================================================*/
57 /*=== MICROCODE RELATED DEFINES ==============================================*/
58 /*============================================================================*/
59
60 /** \brief Magic word for checking correct Endianess of microcode data. */
61 #ifndef DRX_UCODE_MAGIC_WORD
62 #define DRX_UCODE_MAGIC_WORD         ((((u16)'H')<<8)+((u16)'L'))
63 #endif
64
65 /** \brief CRC flag in ucode header, flags field. */
66 #ifndef DRX_UCODE_CRC_FLAG
67 #define DRX_UCODE_CRC_FLAG           (0x0001)
68 #endif
69
70 /** \brief Compression flag in ucode header, flags field. */
71 #ifndef DRX_UCODE_COMPRESSION_FLAG
72 #define DRX_UCODE_COMPRESSION_FLAG   (0x0002)
73 #endif
74
75 /** \brief Maximum size of buffer used to verify the microcode.
76    Must be an even number. */
77 #ifndef DRX_UCODE_MAX_BUF_SIZE
78 #define DRX_UCODE_MAX_BUF_SIZE       (DRXDAP_MAX_RCHUNKSIZE)
79 #endif
80 #if DRX_UCODE_MAX_BUF_SIZE & 1
81 #error DRX_UCODE_MAX_BUF_SIZE must be an even number
82 #endif
83
84 /*============================================================================*/
85 /*=== CHANNEL SCAN RELATED DEFINES ===========================================*/
86 /*============================================================================*/
87
88 /**
89 * \brief Maximum progress indication.
90 *
91 * Progress indication will run from 0 upto DRX_SCAN_MAX_PROGRESS during scan.
92 *
93 */
94 #ifndef DRX_SCAN_MAX_PROGRESS
95 #define DRX_SCAN_MAX_PROGRESS 1000
96 #endif
97
98 /*============================================================================*/
99 /*=== MACROS =================================================================*/
100 /*============================================================================*/
101
102 #define DRX_ISPOWERDOWNMODE(mode) (  ( mode == DRX_POWER_MODE_9  ) || \
103                                        (mode == DRX_POWER_MODE_10) || \
104                                        (mode == DRX_POWER_MODE_11) || \
105                                        (mode == DRX_POWER_MODE_12) || \
106                                        (mode == DRX_POWER_MODE_13) || \
107                                        (mode == DRX_POWER_MODE_14) || \
108                                        (mode == DRX_POWER_MODE_15) || \
109                                        (mode == DRX_POWER_MODE_16) || \
110                                        (mode == DRX_POWER_DOWN) )
111
112 /*------------------------------------------------------------------------------
113 GLOBAL VARIABLES
114 ------------------------------------------------------------------------------*/
115
116 /*------------------------------------------------------------------------------
117 STRUCTURES
118 ------------------------------------------------------------------------------*/
119 /** \brief  Structure of the microcode block headers */
120 typedef struct {
121         u32 addr;
122                   /**<  Destination address of the data in this block */
123         u16 size;
124                   /**<  Size of the block data following this header counted in
125                         16 bits words */
126         u16 flags;
127                   /**<  Flags for this data block:
128                         - bit[0]= CRC on/off
129                         - bit[1]= compression on/off
130                         - bit[15..2]=reserved */
131         u16 CRC;/**<  CRC value of the data block, only valid if CRC flag is
132                         set. */
133 } drxu_code_block_hdr_t, *pdrxu_code_block_hdr_t;
134
135 /*------------------------------------------------------------------------------
136 FUNCTIONS
137 ------------------------------------------------------------------------------*/
138
139 /*============================================================================*/
140 /*============================================================================*/
141 /*== Channel Scan Functions ==================================================*/
142 /*============================================================================*/
143 /*============================================================================*/
144
145 #ifndef DRX_EXCLUDE_SCAN
146
147 /* Prototype of default scanning function */
148 static int
149 scan_function_default(void *scan_context,
150                     drx_scan_command_t scan_command,
151                     pdrx_channel_t scan_channel, bool *get_next_channel);
152
153 /**
154 * \brief Get pointer to scanning function.
155 * \param demod:    Pointer to demodulator instance.
156 * \return drx_scan_func_t.
157 */
158 static drx_scan_func_t get_scan_function(pdrx_demod_instance_t demod)
159 {
160         pdrx_common_attr_t common_attr = (pdrx_common_attr_t) (NULL);
161         drx_scan_func_t scan_func = (drx_scan_func_t) (NULL);
162
163         /* get scan function from common attributes */
164         common_attr = (pdrx_common_attr_t) demod->my_common_attr;
165         scan_func = common_attr->scan_function;
166
167         if (scan_func != NULL) {
168                 /* return device-specific scan function if it's not NULL */
169                 return scan_func;
170         }
171         /* otherwise return default scan function in core driver */
172         return &scan_function_default;
173 }
174
175 /**
176 * \brief Get Context pointer.
177 * \param demod:    Pointer to demodulator instance.
178 * \param scan_context: Context Pointer.
179 * \return drx_scan_func_t.
180 */
181 void *get_scan_context(pdrx_demod_instance_t demod, void *scan_context)
182 {
183         pdrx_common_attr_t common_attr = (pdrx_common_attr_t) (NULL);
184
185         /* get scan function from common attributes */
186         common_attr = (pdrx_common_attr_t) demod->my_common_attr;
187         scan_context = common_attr->scan_context;
188
189         if (scan_context == NULL) {
190                 scan_context = (void *)demod;
191         }
192
193         return scan_context;
194 }
195
196 /**
197 * \brief Wait for lock while scanning.
198 * \param demod:    Pointer to demodulator instance.
199 * \param lock_stat: Pointer to bool indicating if end result is lock or not.
200 * \return int.
201 * \retval DRX_STS_OK:    Success
202 * \retval DRX_STS_ERROR: I2C failure or bsp function failure.
203 *
204 * Wait until timeout, desired lock or NEVER_LOCK.
205 * Assume:
206 * - lock function returns : at least DRX_NOT_LOCKED and a lock state
207 *   higher than DRX_NOT_LOCKED.
208 * - BSP has a clock function to retrieve a millisecond ticker value.
209 * - BSP has a sleep function to enable sleep of n millisecond.
210 *
211 * In case DRX_NEVER_LOCK is returned the poll-wait will be aborted.
212 *
213 */
214 static int scan_wait_for_lock(pdrx_demod_instance_t demod, bool *is_locked)
215 {
216         bool done_waiting = false;
217         drx_lock_status_t lock_state = DRX_NOT_LOCKED;
218         drx_lock_status_t desired_lock_state = DRX_NOT_LOCKED;
219         u32 timeout_value = 0;
220         u32 start_time_lock_stage = 0;
221         u32 current_time = 0;
222         u32 timer_value = 0;
223
224         *is_locked = false;
225         timeout_value = (u32) demod->my_common_attr->scan_demod_lock_timeout;
226         desired_lock_state = demod->my_common_attr->scan_desired_lock;
227         start_time_lock_stage = drxbsp_hst_clock();
228
229         /* Start polling loop, checking for lock & timeout */
230         while (done_waiting == false) {
231
232                 if (drx_ctrl(demod, DRX_CTRL_LOCK_STATUS, &lock_state) !=
233                     DRX_STS_OK) {
234                         return DRX_STS_ERROR;
235                 }
236                 current_time = drxbsp_hst_clock();
237
238                 timer_value = current_time - start_time_lock_stage;
239                 if (lock_state >= desired_lock_state) {
240                         *is_locked = true;
241                         done_waiting = true;
242                 } /* if ( lock_state >= desired_lock_state ) .. */
243                 else if (lock_state == DRX_NEVER_LOCK) {
244                         done_waiting = true;
245                 } /* if ( lock_state == DRX_NEVER_LOCK ) .. */
246                 else if (timer_value > timeout_value) {
247                         /* lock_state == DRX_NOT_LOCKED  and timeout */
248                         done_waiting = true;
249                 } else {
250                         if (drxbsp_hst_sleep(10) != DRX_STS_OK) {
251                                 return DRX_STS_ERROR;
252                         }
253                 }               /* if ( timer_value > timeout_value ) .. */
254
255         }                       /* while */
256
257         return DRX_STS_OK;
258 }
259
260 /*============================================================================*/
261
262 /**
263 * \brief Determine next frequency to scan.
264 * \param demod: Pointer to demodulator instance.
265 * \param skip : Minimum frequency step to take.
266 * \return int.
267 * \retval DRX_STS_OK:          Succes.
268 * \retval DRX_STS_INVALID_ARG: Invalid frequency plan.
269 *
270 * Helper function for ctrl_scan_next() function.
271 * Compute next frequency & index in frequency plan.
272 * Check if scan is ready.
273 *
274 */
275 static int
276 scan_prepare_next_scan(pdrx_demod_instance_t demod, s32 skip)
277 {
278         pdrx_common_attr_t common_attr = (pdrx_common_attr_t) (NULL);
279         u16 table_index = 0;
280         u16 frequency_plan_size = 0;
281         p_drx_frequency_plan_t frequency_plan = (p_drx_frequency_plan_t) (NULL);
282         s32 next_frequency = 0;
283         s32 tuner_min_frequency = 0;
284         s32 tuner_max_frequency = 0;
285
286         common_attr = (pdrx_common_attr_t) demod->my_common_attr;
287         table_index = common_attr->scan_freq_plan_index;
288         frequency_plan = common_attr->scan_param->frequency_plan;
289         next_frequency = common_attr->scan_next_frequency;
290         tuner_min_frequency = common_attr->tuner_min_freq_rf;
291         tuner_max_frequency = common_attr->tuner_max_freq_rf;
292
293         do {
294                 /* Search next frequency to scan */
295
296                 /* always take at least one step */
297                 (common_attr->scan_channelsScanned)++;
298                 next_frequency += frequency_plan[table_index].step;
299                 skip -= frequency_plan[table_index].step;
300
301                 /* and then as many steps necessary to exceed 'skip'
302                    without exceeding end of the band */
303                 while ((skip > 0) &&
304                        (next_frequency <= frequency_plan[table_index].last)) {
305                         (common_attr->scan_channelsScanned)++;
306                         next_frequency += frequency_plan[table_index].step;
307                         skip -= frequency_plan[table_index].step;
308                 }
309                 /* reset skip, in case we move to the next band later */
310                 skip = 0;
311
312                 if (next_frequency > frequency_plan[table_index].last) {
313                         /* reached end of this band */
314                         table_index++;
315                         frequency_plan_size =
316                             common_attr->scan_param->frequency_plan_size;
317                         if (table_index >= frequency_plan_size) {
318                                 /* reached end of frequency plan */
319                                 common_attr->scan_ready = true;
320                         } else {
321                                 next_frequency = frequency_plan[table_index].first;
322                         }
323                 }
324                 if (next_frequency > (tuner_max_frequency)) {
325                         /* reached end of tuner range */
326                         common_attr->scan_ready = true;
327                 }
328         } while ((next_frequency < tuner_min_frequency) &&
329                  (common_attr->scan_ready == false));
330
331         /* Store new values */
332         common_attr->scan_freq_plan_index = table_index;
333         common_attr->scan_next_frequency = next_frequency;
334
335         return DRX_STS_OK;
336 }
337
338 /*============================================================================*/
339
340 /**
341 * \brief Default DTV scanning function.
342 *
343 * \param demod:          Pointer to demodulator instance.
344 * \param scan_command:    Scanning command: INIT, NEXT or STOP.
345 * \param scan_channel:    Channel to check: frequency and bandwidth, others AUTO
346 * \param get_next_channel: Return true if next frequency is desired at next call
347 *
348 * \return int.
349 * \retval DRX_STS_OK:      Channel found, DRX_CTRL_GET_CHANNEL can be used
350 *                             to retrieve channel parameters.
351 * \retval DRX_STS_BUSY:    Channel not found (yet).
352 * \retval DRX_STS_ERROR:   Something went wrong.
353 *
354 * scan_channel and get_next_channel will be NULL for INIT and STOP.
355 */
356 static int
357 scan_function_default(void *scan_context,
358                     drx_scan_command_t scan_command,
359                     pdrx_channel_t scan_channel, bool *get_next_channel)
360 {
361         pdrx_demod_instance_t demod = NULL;
362         int status = DRX_STS_ERROR;
363         bool is_locked = false;
364
365         demod = (pdrx_demod_instance_t) scan_context;
366
367         if (scan_command != DRX_SCAN_COMMAND_NEXT) {
368                 /* just return OK if not doing "scan next" */
369                 return DRX_STS_OK;
370         }
371
372         *get_next_channel = false;
373
374         status = drx_ctrl(demod, DRX_CTRL_SET_CHANNEL, scan_channel);
375         if (status != DRX_STS_OK) {
376                 return (status);
377         }
378
379         status = scan_wait_for_lock(demod, &is_locked);
380         if (status != DRX_STS_OK) {
381                 return status;
382         }
383
384         /* done with this channel, move to next one */
385         *get_next_channel = true;
386
387         if (is_locked == false) {
388                 /* no channel found */
389                 return DRX_STS_BUSY;
390         }
391         /* channel found */
392         return DRX_STS_OK;
393 }
394
395 /*============================================================================*/
396
397 /**
398 * \brief Initialize for channel scan.
399 * \param demod:     Pointer to demodulator instance.
400 * \param scan_param: Pointer to scan parameters.
401 * \return int.
402 * \retval DRX_STS_OK:          Initialized for scan.
403 * \retval DRX_STS_ERROR:       No overlap between frequency plan and tuner
404 *                              range.
405 * \retval DRX_STS_INVALID_ARG: Wrong parameters.
406 *
407 * This function should be called before starting a complete channel scan.
408 * It will prepare everything for a complete channel scan.
409 * After calling this function the DRX_CTRL_SCAN_NEXT control function can be
410 * used to perform the actual scanning. Scanning will start at the first
411 * center frequency of the frequency plan that is within the tuner range.
412 *
413 */
414 static int
415 ctrl_scan_init(pdrx_demod_instance_t demod, p_drx_scan_param_t scan_param)
416 {
417         int status = DRX_STS_ERROR;
418         pdrx_common_attr_t common_attr = (pdrx_common_attr_t) (NULL);
419         s32 max_tuner_freq = 0;
420         s32 min_tuner_freq = 0;
421         u16 nr_channels_in_plan = 0;
422         u16 i = 0;
423         void *scan_context = NULL;
424
425         common_attr = (pdrx_common_attr_t) demod->my_common_attr;
426         common_attr->scan_active = true;
427
428         /* invalidate a previous SCAN_INIT */
429         common_attr->scan_param = (p_drx_scan_param_t) (NULL);
430         common_attr->scan_next_frequency = 0;
431
432         /* Check parameters */
433         if (((demod->my_tuner == NULL) &&
434              (scan_param->num_tries != 1)) ||
435             (scan_param == NULL) ||
436             (scan_param->num_tries == 0) ||
437             (scan_param->frequency_plan == NULL) ||
438             (scan_param->frequency_plan_size == 0)
439             ) {
440                 common_attr->scan_active = false;
441                 return DRX_STS_INVALID_ARG;
442         }
443
444         /* Check frequency plan contents */
445         max_tuner_freq = common_attr->tuner_max_freq_rf;
446         min_tuner_freq = common_attr->tuner_min_freq_rf;
447         for (i = 0; i < (scan_param->frequency_plan_size); i++) {
448                 s32 width = 0;
449                 s32 step = scan_param->frequency_plan[i].step;
450                 s32 first_freq = scan_param->frequency_plan[i].first;
451                 s32 last_freq = scan_param->frequency_plan[i].last;
452                 s32 min_freq = 0;
453                 s32 max_freq = 0;
454
455                 if (step <= 0) {
456                         /* Step must be positive and non-zero */
457                         common_attr->scan_active = false;
458                         return DRX_STS_INVALID_ARG;
459                 }
460
461                 if (first_freq > last_freq) {
462                         /* First center frequency is higher than last center frequency */
463                         common_attr->scan_active = false;
464                         return DRX_STS_INVALID_ARG;
465                 }
466
467                 width = last_freq - first_freq;
468
469                 if ((width % step) != 0) {
470                         /* Difference between last and first center frequency is not
471                            an integer number of steps */
472                         common_attr->scan_active = false;
473                         return DRX_STS_INVALID_ARG;
474                 }
475
476                 /* Check if frequency plan entry intersects with tuner range */
477                 if (last_freq >= min_tuner_freq) {
478                         if (first_freq <= max_tuner_freq) {
479                                 if (first_freq >= min_tuner_freq) {
480                                         min_freq = first_freq;
481                                 } else {
482                                         s32 n = 0;
483
484                                         n = (min_tuner_freq - first_freq) / step;
485                                         if (((min_tuner_freq -
486                                               first_freq) % step) != 0) {
487                                                 n++;
488                                         }
489                                         min_freq = first_freq + n * step;
490                                 }
491
492                                 if (last_freq <= max_tuner_freq) {
493                                         max_freq = last_freq;
494                                 } else {
495                                         s32 n = 0;
496
497                                         n = (last_freq - max_tuner_freq) / step;
498                                         if (((last_freq -
499                                               max_tuner_freq) % step) != 0) {
500                                                 n++;
501                                         }
502                                         max_freq = last_freq - n * step;
503                                 }
504                         }
505                 }
506
507                 /* Keep track of total number of channels within tuner range
508                    in this frequency plan. */
509                 if ((min_freq != 0) && (max_freq != 0)) {
510                         nr_channels_in_plan +=
511                             (u16) (((max_freq - min_freq) / step) + 1);
512
513                         /* Determine first frequency (within tuner range) to scan */
514                         if (common_attr->scan_next_frequency == 0) {
515                                 common_attr->scan_next_frequency = min_freq;
516                                 common_attr->scan_freq_plan_index = i;
517                         }
518                 }
519
520         }                       /* for ( ... ) */
521
522         if (nr_channels_in_plan == 0) {
523                 /* Tuner range and frequency plan ranges do not overlap */
524                 common_attr->scan_active = false;
525                 return DRX_STS_ERROR;
526         }
527
528         /* Store parameters */
529         common_attr->scan_ready = false;
530         common_attr->scan_max_channels = nr_channels_in_plan;
531         common_attr->scan_channelsScanned = 0;
532         common_attr->scan_param = scan_param;   /* SCAN_NEXT is now allowed */
533
534         scan_context = get_scan_context(demod, scan_context);
535
536         status = (*(get_scan_function(demod)))
537             (scan_context, DRX_SCAN_COMMAND_INIT, NULL, NULL);
538
539         common_attr->scan_active = false;
540
541         return DRX_STS_OK;
542 }
543
544 /*============================================================================*/
545
546 /**
547 * \brief Stop scanning.
548 * \param demod:         Pointer to demodulator instance.
549 * \return int.
550 * \retval DRX_STS_OK:          Scan stopped.
551 * \retval DRX_STS_ERROR:       Something went wrong.
552 * \retval DRX_STS_INVALID_ARG: Wrong parameters.
553 */
554 static int ctrl_scan_stop(pdrx_demod_instance_t demod)
555 {
556         int status = DRX_STS_ERROR;
557         pdrx_common_attr_t common_attr = (pdrx_common_attr_t) (NULL);
558         void *scan_context = NULL;
559
560         common_attr = (pdrx_common_attr_t) demod->my_common_attr;
561         common_attr->scan_active = true;
562
563         if ((common_attr->scan_param == NULL) ||
564             (common_attr->scan_max_channels == 0)) {
565                 /* Scan was not running, just return OK */
566                 common_attr->scan_active = false;
567                 return DRX_STS_OK;
568         }
569
570         /* Call default or device-specific scanning stop function */
571         scan_context = get_scan_context(demod, scan_context);
572
573         status = (*(get_scan_function(demod)))
574             (scan_context, DRX_SCAN_COMMAND_STOP, NULL, NULL);
575
576         /* All done, invalidate scan-init */
577         common_attr->scan_param = NULL;
578         common_attr->scan_max_channels = 0;
579         common_attr->scan_active = false;
580
581         return status;
582 }
583
584 /*============================================================================*/
585
586 /**
587 * \brief Scan for next channel.
588 * \param demod:         Pointer to demodulator instance.
589 * \param scan_progress:  Pointer to scan progress.
590 * \return int.
591 * \retval DRX_STS_OK:          Channel found, DRX_CTRL_GET_CHANNEL can be used
592 *                              to retrieve channel parameters.
593 * \retval DRX_STS_BUSY:        Tried part of the channels, as specified in
594 *                              num_tries field of scan parameters. At least one
595 *                              more call to DRX_CTRL_SCAN_NEXT is needed to
596 *                              complete scanning.
597 * \retval DRX_STS_READY:       Reached end of scan range.
598 * \retval DRX_STS_ERROR:       Something went wrong.
599 * \retval DRX_STS_INVALID_ARG: Wrong parameters. The scan_progress may be NULL.
600 *
601 * Progress indication will run from 0 upto DRX_SCAN_MAX_PROGRESS during scan.
602 *
603 */
604 static int ctrl_scan_next(pdrx_demod_instance_t demod, u16 *scan_progress)
605 {
606         pdrx_common_attr_t common_attr = (pdrx_common_attr_t) (NULL);
607         bool *scan_ready = (bool *) (NULL);
608         u16 max_progress = DRX_SCAN_MAX_PROGRESS;
609         u32 num_tries = 0;
610         u32 i = 0;
611
612         common_attr = (pdrx_common_attr_t) demod->my_common_attr;
613
614         /* Check scan parameters */
615         if (scan_progress == NULL) {
616                 common_attr->scan_active = false;
617                 return DRX_STS_INVALID_ARG;
618         }
619
620         *scan_progress = 0;
621         common_attr->scan_active = true;
622         if ((common_attr->scan_param == NULL) ||
623             (common_attr->scan_max_channels == 0)) {
624                 /* ctrl_scan_init() was not called succesfully before ctrl_scan_next() */
625                 common_attr->scan_active = false;
626                 return DRX_STS_ERROR;
627         }
628
629         *scan_progress = (u16) (((common_attr->scan_channelsScanned) *
630                                   ((u32) (max_progress))) /
631                                  (common_attr->scan_max_channels));
632
633         /* Scan */
634         num_tries = common_attr->scan_param->num_tries;
635         scan_ready = &(common_attr->scan_ready);
636
637         for (i = 0; ((i < num_tries) && ((*scan_ready) == false)); i++) {
638                 drx_channel_t scan_channel = { 0 };
639                 int status = DRX_STS_ERROR;
640                 p_drx_frequency_plan_t freq_plan = (p_drx_frequency_plan_t) (NULL);
641                 bool next_channel = false;
642                 void *scan_context = NULL;
643
644                 /* Next channel to scan */
645                 freq_plan =
646                     &(common_attr->scan_param->
647                       frequency_plan[common_attr->scan_freq_plan_index]);
648                 scan_channel.frequency = common_attr->scan_next_frequency;
649                 scan_channel.bandwidth = freq_plan->bandwidth;
650                 scan_channel.mirror = DRX_MIRROR_AUTO;
651                 scan_channel.constellation = DRX_CONSTELLATION_AUTO;
652                 scan_channel.hierarchy = DRX_HIERARCHY_AUTO;
653                 scan_channel.priority = DRX_PRIORITY_HIGH;
654                 scan_channel.coderate = DRX_CODERATE_AUTO;
655                 scan_channel.guard = DRX_GUARD_AUTO;
656                 scan_channel.fftmode = DRX_FFTMODE_AUTO;
657                 scan_channel.classification = DRX_CLASSIFICATION_AUTO;
658                 scan_channel.symbolrate = 0;
659                 scan_channel.interleavemode = DRX_INTERLEAVEMODE_AUTO;
660                 scan_channel.ldpc = DRX_LDPC_AUTO;
661                 scan_channel.carrier = DRX_CARRIER_AUTO;
662                 scan_channel.framemode = DRX_FRAMEMODE_AUTO;
663                 scan_channel.pilot = DRX_PILOT_AUTO;
664
665                 /* Call default or device-specific scanning function */
666                 scan_context = get_scan_context(demod, scan_context);
667
668                 status = (*(get_scan_function(demod)))
669                     (scan_context, DRX_SCAN_COMMAND_NEXT, &scan_channel,
670                      &next_channel);
671
672                 /* Proceed to next channel if requested */
673                 if (next_channel == true) {
674                         int next_status = DRX_STS_ERROR;
675                         s32 skip = 0;
676
677                         if (status == DRX_STS_OK) {
678                                 /* a channel was found, so skip some frequency steps */
679                                 skip = common_attr->scan_param->skip;
680                         }
681                         next_status = scan_prepare_next_scan(demod, skip);
682
683                         /* keep track of progress */
684                         *scan_progress =
685                             (u16) (((common_attr->scan_channelsScanned) *
686                                       ((u32) (max_progress))) /
687                                      (common_attr->scan_max_channels));
688
689                         if (next_status != DRX_STS_OK) {
690                                 common_attr->scan_active = false;
691                                 return (next_status);
692                         }
693                 }
694                 if (status != DRX_STS_BUSY) {
695                         /* channel found or error */
696                         common_attr->scan_active = false;
697                         return status;
698                 }
699         }                       /* for ( i = 0; i < ( ... num_tries); i++) */
700
701         if ((*scan_ready) == true) {
702                 /* End of scan reached: call stop-scan, ignore any error */
703                 ctrl_scan_stop(demod);
704                 common_attr->scan_active = false;
705                 return (DRX_STS_READY);
706         }
707
708         common_attr->scan_active = false;
709
710         return DRX_STS_BUSY;
711 }
712
713 #endif /* #ifndef DRX_EXCLUDE_SCAN */
714
715 /*============================================================================*/
716
717 /**
718 * \brief Program tuner.
719 * \param demod:         Pointer to demodulator instance.
720 * \param tunerChannel:  Pointer to tuning parameters.
721 * \return int.
722 * \retval DRX_STS_OK:          Tuner programmed successfully.
723 * \retval DRX_STS_ERROR:       Something went wrong.
724 * \retval DRX_STS_INVALID_ARG: Wrong parameters.
725 *
726 * tunerChannel passes parameters to program the tuner,
727 * but also returns the actual RF and IF frequency from the tuner.
728 *
729 */
730 static int
731 ctrl_program_tuner(pdrx_demod_instance_t demod, pdrx_channel_t channel)
732 {
733         pdrx_common_attr_t common_attr = (pdrx_common_attr_t) (NULL);
734         enum drx_standard standard = DRX_STANDARD_UNKNOWN;
735         u32 tuner_mode = 0;
736         int status = DRX_STS_ERROR;
737         s32 if_frequency = 0;
738         bool tuner_slow_mode = false;
739
740         /* can't tune without a tuner */
741         if (demod->my_tuner == NULL) {
742                 return DRX_STS_INVALID_ARG;
743         }
744
745         common_attr = (pdrx_common_attr_t) demod->my_common_attr;
746
747         /* select analog or digital tuner mode based on current standard */
748         if (drx_ctrl(demod, DRX_CTRL_GET_STANDARD, &standard) != DRX_STS_OK) {
749                 return DRX_STS_ERROR;
750         }
751
752         if (DRX_ISATVSTD(standard)) {
753                 tuner_mode |= TUNER_MODE_ANALOG;
754         } else {                /* note: also for unknown standard */
755
756                 tuner_mode |= TUNER_MODE_DIGITAL;
757         }
758
759         /* select tuner bandwidth */
760         switch (channel->bandwidth) {
761         case DRX_BANDWIDTH_6MHZ:
762                 tuner_mode |= TUNER_MODE_6MHZ;
763                 break;
764         case DRX_BANDWIDTH_7MHZ:
765                 tuner_mode |= TUNER_MODE_7MHZ;
766                 break;
767         case DRX_BANDWIDTH_8MHZ:
768                 tuner_mode |= TUNER_MODE_8MHZ;
769                 break;
770         default:                /* note: also for unknown bandwidth */
771                 return DRX_STS_INVALID_ARG;
772         }
773
774         DRX_GET_TUNERSLOWMODE(demod, tuner_slow_mode);
775
776         /* select fast (switch) or slow (lock) tuner mode */
777         if (tuner_slow_mode) {
778                 tuner_mode |= TUNER_MODE_LOCK;
779         } else {
780                 tuner_mode |= TUNER_MODE_SWITCH;
781         }
782
783         if (common_attr->tuner_port_nr == 1) {
784                 bool bridge_closed = true;
785                 int status_bridge = DRX_STS_ERROR;
786
787                 status_bridge =
788                     drx_ctrl(demod, DRX_CTRL_I2C_BRIDGE, &bridge_closed);
789                 if (status_bridge != DRX_STS_OK) {
790                         return status_bridge;
791                 }
792         }
793
794         status = drxbsp_tuner_set_frequency(demod->my_tuner,
795                                            tuner_mode, channel->frequency);
796
797         /* attempt restoring bridge before checking status of set_frequency */
798         if (common_attr->tuner_port_nr == 1) {
799                 bool bridge_closed = false;
800                 int status_bridge = DRX_STS_ERROR;
801
802                 status_bridge =
803                     drx_ctrl(demod, DRX_CTRL_I2C_BRIDGE, &bridge_closed);
804                 if (status_bridge != DRX_STS_OK) {
805                         return status_bridge;
806                 }
807         }
808
809         /* now check status of drxbsp_tuner_set_frequency */
810         if (status != DRX_STS_OK) {
811                 return status;
812         }
813
814         /* get actual RF and IF frequencies from tuner */
815         status = drxbsp_tuner_get_frequency(demod->my_tuner,
816                                            tuner_mode,
817                                            &(channel->frequency),
818                                            &(if_frequency));
819         if (status != DRX_STS_OK) {
820                 return status;
821         }
822
823         /* update common attributes with information available from this function;
824            TODO: check if this is required and safe */
825         DRX_SET_INTERMEDIATEFREQ(demod, if_frequency);
826
827         return DRX_STS_OK;
828 }
829
830 /*============================================================================*/
831
832 /**
833 * \brief function to do a register dump.
834 * \param demod:            Pointer to demodulator instance.
835 * \param registers:        Registers to dump.
836 * \return int.
837 * \retval DRX_STS_OK:          Dump executed successfully.
838 * \retval DRX_STS_ERROR:       Something went wrong.
839 * \retval DRX_STS_INVALID_ARG: Wrong parameters.
840 *
841 */
842 int ctrl_dump_registers(pdrx_demod_instance_t demod,
843                               p_drx_reg_dump_t registers)
844 {
845         u16 i = 0;
846
847         if (registers == NULL) {
848                 /* registers not supplied */
849                 return DRX_STS_INVALID_ARG;
850         }
851
852         /* start dumping registers */
853         while (registers[i].address != 0) {
854                 int status = DRX_STS_ERROR;
855                 u16 value = 0;
856                 u32 data = 0;
857
858                 status =
859                     demod->my_access_funct->read_reg16func(demod->my_i2c_dev_addr,
860                                                         registers[i].address,
861                                                         &value, 0);
862
863                 data = (u32) value;
864
865                 if (status != DRX_STS_OK) {
866                         /* no breakouts;
867                            depending on device ID, some HW blocks might not be available */
868                         data |= ((u32) status) << 16;
869                 }
870                 registers[i].data = data;
871                 i++;
872         }
873
874         /* all done, all OK (any errors are saved inside data) */
875         return DRX_STS_OK;
876 }
877
878 /*============================================================================*/
879 /*============================================================================*/
880 /*===Microcode related functions==============================================*/
881 /*============================================================================*/
882 /*============================================================================*/
883
884 /**
885 * \brief Read a 16 bits word, expects big endian data.
886 * \param addr: Pointer to memory from which to read the 16 bits word.
887 * \return u16 The data read.
888 *
889 * This function takes care of the possible difference in endianness between the
890 * host and the data contained in the microcode image file.
891 *
892 */
893 static u16 u_code_read16(u8 *addr)
894 {
895         /* Works fo any host processor */
896
897         u16 word = 0;
898
899         word = ((u16) addr[0]);
900         word <<= 8;
901         word |= ((u16) addr[1]);
902
903         return word;
904 }
905
906 /*============================================================================*/
907
908 /**
909 * \brief Read a 32 bits word, expects big endian data.
910 * \param addr: Pointer to memory from which to read the 32 bits word.
911 * \return u32 The data read.
912 *
913 * This function takes care of the possible difference in endianness between the
914 * host and the data contained in the microcode image file.
915 *
916 */
917 static u32 u_code_read32(u8 *addr)
918 {
919         /* Works fo any host processor */
920
921         u32 word = 0;
922
923         word = ((u16) addr[0]);
924         word <<= 8;
925         word |= ((u16) addr[1]);
926         word <<= 8;
927         word |= ((u16) addr[2]);
928         word <<= 8;
929         word |= ((u16) addr[3]);
930
931         return word;
932 }
933
934 /*============================================================================*/
935
936 /**
937 * \brief Compute CRC of block of microcode data.
938 * \param block_data: Pointer to microcode data.
939 * \param nr_words:   Size of microcode block (number of 16 bits words).
940 * \return u16 The computed CRC residu.
941 */
942 static u16 u_code_compute_crc(u8 *block_data, u16 nr_words)
943 {
944         u16 i = 0;
945         u16 j = 0;
946         u32 crc_word = 0;
947         u32 carry = 0;
948
949         while (i < nr_words) {
950                 crc_word |= (u32) u_code_read16(block_data);
951                 for (j = 0; j < 16; j++) {
952                         crc_word <<= 1;
953                         if (carry != 0) {
954                                 crc_word ^= 0x80050000UL;
955                         }
956                         carry = crc_word & 0x80000000UL;
957                 }
958                 i++;
959                 block_data += (sizeof(u16));
960         }
961         return ((u16) (crc_word >> 16));
962 }
963
964 /*============================================================================*/
965
966 /**
967 * \brief Handle microcode upload or verify.
968 * \param dev_addr: Address of device.
969 * \param mc_info:  Pointer to information about microcode data.
970 * \param action:  Either UCODE_UPLOAD or UCODE_VERIFY
971 * \return int.
972 * \retval DRX_STS_OK:
973 *                    - In case of UCODE_UPLOAD: code is successfully uploaded.
974 *                    - In case of UCODE_VERIFY: image on device is equal to
975 *                      image provided to this control function.
976 * \retval DRX_STS_ERROR:
977 *                    - In case of UCODE_UPLOAD: I2C error.
978 *                    - In case of UCODE_VERIFY: I2C error or image on device
979 *                      is not equal to image provided to this control function.
980 * \retval DRX_STS_INVALID_ARG:
981 *                    - Invalid arguments.
982 *                    - Provided image is corrupt
983 */
984 static int
985 ctrl_u_code(pdrx_demod_instance_t demod,
986           p_drxu_code_info_t mc_info, drxu_code_action_t action)
987 {
988         int rc;
989         u16 i = 0;
990         u16 mc_nr_of_blks = 0;
991         u16 mc_magic_word = 0;
992         u8 *mc_data = (u8 *) (NULL);
993         struct i2c_device_addr *dev_addr = (struct i2c_device_addr *) (NULL);
994
995         dev_addr = demod->my_i2c_dev_addr;
996
997         /* Check arguments */
998         if ((mc_info == NULL) || (mc_info->mc_data == NULL)) {
999                 return DRX_STS_INVALID_ARG;
1000         }
1001
1002         mc_data = mc_info->mc_data;
1003
1004         /* Check data */
1005         mc_magic_word = u_code_read16(mc_data);
1006         mc_data += sizeof(u16);
1007         mc_nr_of_blks = u_code_read16(mc_data);
1008         mc_data += sizeof(u16);
1009
1010         if ((mc_magic_word != DRX_UCODE_MAGIC_WORD) || (mc_nr_of_blks == 0)) {
1011                 /* wrong endianess or wrong data ? */
1012                 return DRX_STS_INVALID_ARG;
1013         }
1014
1015         /* Scan microcode blocks first for version info if uploading */
1016         if (action == UCODE_UPLOAD) {
1017                 /* Clear version block */
1018                 DRX_SET_MCVERTYPE(demod, 0);
1019                 DRX_SET_MCDEV(demod, 0);
1020                 DRX_SET_MCVERSION(demod, 0);
1021                 DRX_SET_MCPATCH(demod, 0);
1022                 for (i = 0; i < mc_nr_of_blks; i++) {
1023                         drxu_code_block_hdr_t block_hdr;
1024
1025                         /* Process block header */
1026                         block_hdr.addr = u_code_read32(mc_data);
1027                         mc_data += sizeof(u32);
1028                         block_hdr.size = u_code_read16(mc_data);
1029                         mc_data += sizeof(u16);
1030                         block_hdr.flags = u_code_read16(mc_data);
1031                         mc_data += sizeof(u16);
1032                         block_hdr.CRC = u_code_read16(mc_data);
1033                         mc_data += sizeof(u16);
1034
1035                         if (block_hdr.flags & 0x8) {
1036                                 /* Aux block. Check type */
1037                                 u8 *auxblk = mc_info->mc_data + block_hdr.addr;
1038                                 u16 auxtype = u_code_read16(auxblk);
1039                                 if (DRX_ISMCVERTYPE(auxtype)) {
1040                                         DRX_SET_MCVERTYPE(demod,
1041                                                           u_code_read16(auxblk));
1042                                         auxblk += sizeof(u16);
1043                                         DRX_SET_MCDEV(demod,
1044                                                       u_code_read32(auxblk));
1045                                         auxblk += sizeof(u32);
1046                                         DRX_SET_MCVERSION(demod,
1047                                                           u_code_read32(auxblk));
1048                                         auxblk += sizeof(u32);
1049                                         DRX_SET_MCPATCH(demod,
1050                                                         u_code_read32(auxblk));
1051                                 }
1052                         }
1053
1054                         /* Next block */
1055                         mc_data += block_hdr.size * sizeof(u16);
1056                 }
1057
1058                 /* After scanning, validate the microcode.
1059                    It is also valid if no validation control exists.
1060                  */
1061                 rc = drx_ctrl(demod, DRX_CTRL_VALIDATE_UCODE, NULL);
1062                 if (rc != DRX_STS_OK && rc != DRX_STS_FUNC_NOT_AVAILABLE) {
1063                         return rc;
1064                 }
1065
1066                 /* Restore data pointer */
1067                 mc_data = mc_info->mc_data + 2 * sizeof(u16);
1068         }
1069
1070         /* Process microcode blocks */
1071         for (i = 0; i < mc_nr_of_blks; i++) {
1072                 drxu_code_block_hdr_t block_hdr;
1073                 u16 mc_block_nr_bytes = 0;
1074
1075                 /* Process block header */
1076                 block_hdr.addr = u_code_read32(mc_data);
1077                 mc_data += sizeof(u32);
1078                 block_hdr.size = u_code_read16(mc_data);
1079                 mc_data += sizeof(u16);
1080                 block_hdr.flags = u_code_read16(mc_data);
1081                 mc_data += sizeof(u16);
1082                 block_hdr.CRC = u_code_read16(mc_data);
1083                 mc_data += sizeof(u16);
1084
1085                 /* Check block header on:
1086                    - data larger than 64Kb
1087                    - if CRC enabled check CRC
1088                  */
1089                 if ((block_hdr.size > 0x7FFF) ||
1090                     (((block_hdr.flags & DRX_UCODE_CRC_FLAG) != 0) &&
1091                      (block_hdr.CRC != u_code_compute_crc(mc_data, block_hdr.size)))
1092                     ) {
1093                         /* Wrong data ! */
1094                         return DRX_STS_INVALID_ARG;
1095                 }
1096
1097                 mc_block_nr_bytes = block_hdr.size * ((u16) sizeof(u16));
1098
1099                 if (block_hdr.size != 0) {
1100                         /* Perform the desired action */
1101                         switch (action) {
1102             /*================================================================*/
1103                         case UCODE_UPLOAD:
1104                                 {
1105                                         /* Upload microcode */
1106                                         if (demod->my_access_funct->
1107                                             write_block_func(dev_addr,
1108                                                            (dr_xaddr_t) block_hdr.
1109                                                            addr, mc_block_nr_bytes,
1110                                                            mc_data,
1111                                                            0x0000) !=
1112                                             DRX_STS_OK) {
1113                                                 return (DRX_STS_ERROR);
1114                                         }       /* if */
1115                                 };
1116                                 break;
1117
1118             /*================================================================*/
1119                         case UCODE_VERIFY:
1120                                 {
1121                                         int result = 0;
1122                                         u8 mc_dataBuffer
1123                                             [DRX_UCODE_MAX_BUF_SIZE];
1124                                         u32 bytes_to_compare = 0;
1125                                         u32 bytes_left_to_compare = 0;
1126                                         dr_xaddr_t curr_addr = (dr_xaddr_t) 0;
1127                                         u8 *curr_ptr = NULL;
1128
1129                                         bytes_left_to_compare = mc_block_nr_bytes;
1130                                         curr_addr = block_hdr.addr;
1131                                         curr_ptr = mc_data;
1132
1133                                         while (bytes_left_to_compare != 0) {
1134                                                 if (bytes_left_to_compare >
1135                                                     ((u32)
1136                                                      DRX_UCODE_MAX_BUF_SIZE)) {
1137                                                         bytes_to_compare =
1138                                                             ((u32)
1139                                                              DRX_UCODE_MAX_BUF_SIZE);
1140                                                 } else {
1141                                                         bytes_to_compare =
1142                                                             bytes_left_to_compare;
1143                                                 }
1144
1145                                                 if (demod->my_access_funct->
1146                                                     read_block_func(dev_addr,
1147                                                                   curr_addr,
1148                                                                   (u16)
1149                                                                   bytes_to_compare,
1150                                                                   (u8 *)
1151                                                                   mc_dataBuffer,
1152                                                                   0x0000) !=
1153                                                     DRX_STS_OK) {
1154                                                         return (DRX_STS_ERROR);
1155                                                 }
1156
1157                                                 result =
1158                                                     drxbsp_hst_memcmp(curr_ptr,
1159                                                                       mc_dataBuffer,
1160                                                                       bytes_to_compare);
1161
1162                                                 if (result != 0) {
1163                                                         return DRX_STS_ERROR;
1164                                                 }
1165
1166                                                 curr_addr +=
1167                                                     ((dr_xaddr_t)
1168                                                      (bytes_to_compare / 2));
1169                                                 curr_ptr =
1170                                                     &(curr_ptr[bytes_to_compare]);
1171                                                 bytes_left_to_compare -=
1172                                                     ((u32) bytes_to_compare);
1173                                         }       /* while( bytes_to_compare > DRX_UCODE_MAX_BUF_SIZE ) */
1174                                 };
1175                                 break;
1176
1177             /*================================================================*/
1178                         default:
1179                                 return DRX_STS_INVALID_ARG;
1180                                 break;
1181
1182                         }       /* switch ( action ) */
1183                 }
1184
1185                 /* if (block_hdr.size != 0 ) */
1186                 /* Next block */
1187                 mc_data += mc_block_nr_bytes;
1188
1189         }                       /* for( i = 0 ; i<mc_nr_of_blks ; i++ ) */
1190
1191         return DRX_STS_OK;
1192 }
1193
1194 /*============================================================================*/
1195
1196 /**
1197 * \brief Build list of version information.
1198 * \param demod: A pointer to a demodulator instance.
1199 * \param version_list: Pointer to linked list of versions.
1200 * \return int.
1201 * \retval DRX_STS_OK:          Version information stored in version_list
1202 * \retval DRX_STS_INVALID_ARG: Invalid arguments.
1203 */
1204 static int
1205 ctrl_version(pdrx_demod_instance_t demod, p_drx_version_list_t *version_list)
1206 {
1207         static char drx_driver_core_module_name[] = "Core driver";
1208         static char drx_driver_core_version_text[] =
1209             DRX_VERSIONSTRING(VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH);
1210
1211         static drx_version_t drx_driver_core_version;
1212         static drx_version_list_t drx_driver_core_versionList;
1213
1214         p_drx_version_list_t demod_version_list = (p_drx_version_list_t) (NULL);
1215         int return_status = DRX_STS_ERROR;
1216
1217         /* Check arguments */
1218         if (version_list == NULL) {
1219                 return DRX_STS_INVALID_ARG;
1220         }
1221
1222         /* Get version info list from demod */
1223         return_status = (*(demod->my_demod_funct->ctrl_func)) (demod,
1224                                                            DRX_CTRL_VERSION,
1225                                                            (void *)
1226                                                            &demod_version_list);
1227
1228         /* Always fill in the information of the driver SW . */
1229         drx_driver_core_version.module_type = DRX_MODULE_DRIVERCORE;
1230         drx_driver_core_version.module_name = drx_driver_core_module_name;
1231         drx_driver_core_version.v_major = VERSION_MAJOR;
1232         drx_driver_core_version.v_minor = VERSION_MINOR;
1233         drx_driver_core_version.v_patch = VERSION_PATCH;
1234         drx_driver_core_version.v_string = drx_driver_core_version_text;
1235
1236         drx_driver_core_versionList.version = &drx_driver_core_version;
1237         drx_driver_core_versionList.next = (p_drx_version_list_t) (NULL);
1238
1239         if ((return_status == DRX_STS_OK) && (demod_version_list != NULL)) {
1240                 /* Append versioninfo from driver to versioninfo from demod  */
1241                 /* Return version info in "bottom-up" order. This way, multiple
1242                    devices can be handled without using malloc. */
1243                 p_drx_version_list_t current_list_element = demod_version_list;
1244                 while (current_list_element->next != NULL) {
1245                         current_list_element = current_list_element->next;
1246                 }
1247                 current_list_element->next = &drx_driver_core_versionList;
1248
1249                 *version_list = demod_version_list;
1250         } else {
1251                 /* Just return versioninfo from driver */
1252                 *version_list = &drx_driver_core_versionList;
1253         }
1254
1255         return DRX_STS_OK;
1256 }
1257
1258 /*============================================================================*/
1259 /*============================================================================*/
1260 /*== Exported functions ======================================================*/
1261 /*============================================================================*/
1262 /*============================================================================*/
1263
1264 /**
1265 * \brief This function is obsolete.
1266 * \param demods: Don't care, parameter is ignored.
1267 * \return int Return status.
1268 * \retval DRX_STS_OK: Initialization completed.
1269 *
1270 * This function is obsolete, prototype available for backward compatability.
1271 *
1272 */
1273
1274 int drx_init(pdrx_demod_instance_t demods[])
1275 {
1276         return DRX_STS_OK;
1277 }
1278
1279 /*============================================================================*/
1280
1281 /**
1282 * \brief This function is obsolete.
1283 * \return int Return status.
1284 * \retval DRX_STS_OK: Terminated driver successful.
1285 *
1286 * This function is obsolete, prototype available for backward compatability.
1287 *
1288 */
1289
1290 int drx_term(void)
1291 {
1292         return DRX_STS_OK;
1293 }
1294
1295 /*============================================================================*/
1296
1297 /**
1298 * \brief Open a demodulator instance.
1299 * \param demod: A pointer to a demodulator instance.
1300 * \return int Return status.
1301 * \retval DRX_STS_OK:          Opened demod instance with succes.
1302 * \retval DRX_STS_ERROR:       Driver not initialized or unable to initialize
1303 *                              demod.
1304 * \retval DRX_STS_INVALID_ARG: Demod instance has invalid content.
1305 *
1306 */
1307
1308 int drx_open(pdrx_demod_instance_t demod)
1309 {
1310         int status = DRX_STS_OK;
1311
1312         if ((demod == NULL) ||
1313             (demod->my_demod_funct == NULL) ||
1314             (demod->my_common_attr == NULL) ||
1315             (demod->my_ext_attr == NULL) ||
1316             (demod->my_i2c_dev_addr == NULL) ||
1317             (demod->my_common_attr->is_opened == true)) {
1318                 return (DRX_STS_INVALID_ARG);
1319         }
1320
1321         status = (*(demod->my_demod_funct->open_func)) (demod);
1322
1323         if (status == DRX_STS_OK) {
1324                 demod->my_common_attr->is_opened = true;
1325         }
1326
1327         return status;
1328 }
1329
1330 /*============================================================================*/
1331
1332 /**
1333 * \brief Close device.
1334 * \param demod: A pointer to a demodulator instance.
1335 * \return int Return status.
1336 * \retval DRX_STS_OK:          Closed demod instance with succes.
1337 * \retval DRX_STS_ERROR:       Driver not initialized or error during close
1338 *                              demod.
1339 * \retval DRX_STS_INVALID_ARG: Demod instance has invalid content.
1340 *
1341 * Free resources occupied by device instance.
1342 * Put device into sleep mode.
1343 */
1344
1345 int drx_close(pdrx_demod_instance_t demod)
1346 {
1347         int status = DRX_STS_OK;
1348
1349         if ((demod == NULL) ||
1350             (demod->my_demod_funct == NULL) ||
1351             (demod->my_common_attr == NULL) ||
1352             (demod->my_ext_attr == NULL) ||
1353             (demod->my_i2c_dev_addr == NULL) ||
1354             (demod->my_common_attr->is_opened == false)) {
1355                 return DRX_STS_INVALID_ARG;
1356         }
1357
1358         status = (*(demod->my_demod_funct->close_func)) (demod);
1359
1360         DRX_SET_ISOPENED(demod, false);
1361
1362         return status;
1363 }
1364
1365 /*============================================================================*/
1366
1367 /**
1368 * \brief Control the device.
1369 * \param demod:    A pointer to a demodulator instance.
1370 * \param ctrl:     Reference to desired control function.
1371 * \param ctrl_data: Pointer to data structure for control function.
1372 * \return int Return status.
1373 * \retval DRX_STS_OK:                 Control function completed successfully.
1374 * \retval DRX_STS_ERROR:              Driver not initialized or error during
1375 *                                     control demod.
1376 * \retval DRX_STS_INVALID_ARG:        Demod instance or ctrl_data has invalid
1377 *                                     content.
1378 * \retval DRX_STS_FUNC_NOT_AVAILABLE: Specified control function is not
1379 *                                     available.
1380 *
1381 * Data needed or returned by the control function is stored in ctrl_data.
1382 *
1383 */
1384
1385 int
1386 drx_ctrl(pdrx_demod_instance_t demod, u32 ctrl, void *ctrl_data)
1387 {
1388         int status = DRX_STS_ERROR;
1389
1390         if ((demod == NULL) ||
1391             (demod->my_demod_funct == NULL) ||
1392             (demod->my_common_attr == NULL) ||
1393             (demod->my_ext_attr == NULL) || (demod->my_i2c_dev_addr == NULL)
1394             ) {
1395                 return (DRX_STS_INVALID_ARG);
1396         }
1397
1398         if (((demod->my_common_attr->is_opened == false) &&
1399              (ctrl != DRX_CTRL_PROBE_DEVICE) && (ctrl != DRX_CTRL_VERSION))
1400             ) {
1401                 return (DRX_STS_INVALID_ARG);
1402         }
1403
1404         if ((DRX_ISPOWERDOWNMODE(demod->my_common_attr->current_power_mode) &&
1405              (ctrl != DRX_CTRL_POWER_MODE) &&
1406              (ctrl != DRX_CTRL_PROBE_DEVICE) &&
1407              (ctrl != DRX_CTRL_NOP) && (ctrl != DRX_CTRL_VERSION)
1408             )
1409             ) {
1410                 return DRX_STS_FUNC_NOT_AVAILABLE;
1411         }
1412
1413         /* Fixed control functions */
1414         switch (ctrl) {
1415       /*======================================================================*/
1416         case DRX_CTRL_NOP:
1417                 /* No operation */
1418                 return DRX_STS_OK;
1419                 break;
1420
1421       /*======================================================================*/
1422         case DRX_CTRL_VERSION:
1423                 return ctrl_version(demod, (p_drx_version_list_t *) ctrl_data);
1424                 break;
1425
1426       /*======================================================================*/
1427         default:
1428                 /* Do nothing */
1429                 break;
1430         }
1431
1432         /* Virtual functions */
1433         /* First try calling function from derived class */
1434         status = (*(demod->my_demod_funct->ctrl_func)) (demod, ctrl, ctrl_data);
1435         if (status == DRX_STS_FUNC_NOT_AVAILABLE) {
1436                 /* Now try calling a the base class function */
1437                 switch (ctrl) {
1438          /*===================================================================*/
1439                 case DRX_CTRL_LOAD_UCODE:
1440                         return ctrl_u_code(demod,
1441                                          (p_drxu_code_info_t) ctrl_data,
1442                                          UCODE_UPLOAD);
1443                         break;
1444
1445          /*===================================================================*/
1446                 case DRX_CTRL_VERIFY_UCODE:
1447                         {
1448                                 return ctrl_u_code(demod,
1449                                                  (p_drxu_code_info_t) ctrl_data,
1450                                                  UCODE_VERIFY);
1451                         }
1452                         break;
1453
1454 #ifndef DRX_EXCLUDE_SCAN
1455          /*===================================================================*/
1456                 case DRX_CTRL_SCAN_INIT:
1457                         {
1458                                 return ctrl_scan_init(demod,
1459                                                     (p_drx_scan_param_t) ctrl_data);
1460                         }
1461                         break;
1462
1463          /*===================================================================*/
1464                 case DRX_CTRL_SCAN_NEXT:
1465                         {
1466                                 return ctrl_scan_next(demod, (u16 *) ctrl_data);
1467                         }
1468                         break;
1469
1470          /*===================================================================*/
1471                 case DRX_CTRL_SCAN_STOP:
1472                         {
1473                                 return ctrl_scan_stop(demod);
1474                         }
1475                         break;
1476 #endif /* #ifndef DRX_EXCLUDE_SCAN */
1477
1478          /*===================================================================*/
1479                 case DRX_CTRL_PROGRAM_TUNER:
1480                         {
1481                                 return ctrl_program_tuner(demod,
1482                                                         (pdrx_channel_t)
1483                                                         ctrl_data);
1484                         }
1485                         break;
1486
1487          /*===================================================================*/
1488                 case DRX_CTRL_DUMP_REGISTERS:
1489                         {
1490                                 return ctrl_dump_registers(demod,
1491                                                          (p_drx_reg_dump_t)
1492                                                          ctrl_data);
1493                         }
1494                         break;
1495
1496          /*===================================================================*/
1497                 default:
1498                         return DRX_STS_FUNC_NOT_AVAILABLE;
1499                 }
1500         } else {
1501                 return (status);
1502         }
1503
1504         return DRX_STS_OK;
1505 }
1506
1507 /*============================================================================*/
1508
1509 /* END OF FILE */