2 Copyright (c), 2004-2005,2007-2010 Trident Microsystems, Inc.
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
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
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.
32 * \file $Id: drx_driver.c,v 1.40 2010/01/12 01:24:56 lfeng Exp $
34 * \brief Generic DRX functionality, DRX driver core.
38 /*------------------------------------------------------------------------------
40 ------------------------------------------------------------------------------*/
41 #include "drx_driver.h"
43 #define VERSION_FIXED 0
45 #define VERSION_MAJOR 0
46 #define VERSION_MINOR 0
47 #define VERSION_PATCH 0
49 #include "drx_driver_version.h"
52 /*------------------------------------------------------------------------------
54 ------------------------------------------------------------------------------*/
56 /*============================================================================*/
57 /*=== MICROCODE RELATED DEFINES ==============================================*/
58 /*============================================================================*/
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'))
65 /** \brief CRC flag in ucode header, flags field. */
66 #ifndef DRX_UCODE_CRC_FLAG
67 #define DRX_UCODE_CRC_FLAG (0x0001)
70 /** \brief Compression flag in ucode header, flags field. */
71 #ifndef DRX_UCODE_COMPRESSION_FLAG
72 #define DRX_UCODE_COMPRESSION_FLAG (0x0002)
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)
80 #if DRX_UCODE_MAX_BUF_SIZE & 1
81 #error DRX_UCODE_MAX_BUF_SIZE must be an even number
84 /*============================================================================*/
85 /*=== CHANNEL SCAN RELATED DEFINES ===========================================*/
86 /*============================================================================*/
89 * \brief Maximum progress indication.
91 * Progress indication will run from 0 upto DRX_SCAN_MAX_PROGRESS during scan.
94 #ifndef DRX_SCAN_MAX_PROGRESS
95 #define DRX_SCAN_MAX_PROGRESS 1000
98 /*============================================================================*/
99 /*=== MACROS =================================================================*/
100 /*============================================================================*/
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) )
112 /*------------------------------------------------------------------------------
114 ------------------------------------------------------------------------------*/
116 /*------------------------------------------------------------------------------
118 ------------------------------------------------------------------------------*/
119 /** \brief Structure of the microcode block headers */
122 /**< Destination address of the data in this block */
124 /**< Size of the block data following this header counted in
127 /**< Flags for this data block:
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
133 } drxu_code_block_hdr_t, *pdrxu_code_block_hdr_t;
135 /*------------------------------------------------------------------------------
137 ------------------------------------------------------------------------------*/
139 /*============================================================================*/
140 /*============================================================================*/
141 /*== Channel Scan Functions ==================================================*/
142 /*============================================================================*/
143 /*============================================================================*/
145 #ifndef DRX_EXCLUDE_SCAN
147 /* Prototype of default scanning function */
149 scan_function_default(void *scan_context,
150 drx_scan_command_t scan_command,
151 pdrx_channel_t scan_channel, bool *get_next_channel);
154 * \brief Get pointer to scanning function.
155 * \param demod: Pointer to demodulator instance.
156 * \return drx_scan_func_t.
158 static drx_scan_func_t get_scan_function(pdrx_demod_instance_t demod)
160 pdrx_common_attr_t common_attr = (pdrx_common_attr_t) (NULL);
161 drx_scan_func_t scan_func = (drx_scan_func_t) (NULL);
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;
167 if (scan_func != NULL) {
168 /* return device-specific scan function if it's not NULL */
171 /* otherwise return default scan function in core driver */
172 return &scan_function_default;
176 * \brief Get Context pointer.
177 * \param demod: Pointer to demodulator instance.
178 * \param scan_context: Context Pointer.
179 * \return drx_scan_func_t.
181 void *get_scan_context(pdrx_demod_instance_t demod, void *scan_context)
183 pdrx_common_attr_t common_attr = (pdrx_common_attr_t) (NULL);
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;
189 if (scan_context == NULL) {
190 scan_context = (void *)demod;
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.
201 * \retval DRX_STS_OK: Success
202 * \retval DRX_STS_ERROR: I2C failure or bsp function failure.
204 * Wait until timeout, desired lock or NEVER_LOCK.
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.
211 * In case DRX_NEVER_LOCK is returned the poll-wait will be aborted.
214 static int scan_wait_for_lock(pdrx_demod_instance_t demod, bool *is_locked)
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;
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();
229 /* Start polling loop, checking for lock & timeout */
230 while (done_waiting == false) {
232 if (drx_ctrl(demod, DRX_CTRL_LOCK_STATUS, &lock_state) !=
234 return DRX_STS_ERROR;
236 current_time = drxbsp_hst_clock();
238 timer_value = current_time - start_time_lock_stage;
239 if (lock_state >= desired_lock_state) {
242 } /* if ( lock_state >= desired_lock_state ) .. */
243 else if (lock_state == DRX_NEVER_LOCK) {
245 } /* if ( lock_state == DRX_NEVER_LOCK ) .. */
246 else if (timer_value > timeout_value) {
247 /* lock_state == DRX_NOT_LOCKED and timeout */
250 if (drxbsp_hst_sleep(10) != DRX_STS_OK) {
251 return DRX_STS_ERROR;
253 } /* if ( timer_value > timeout_value ) .. */
260 /*============================================================================*/
263 * \brief Determine next frequency to scan.
264 * \param demod: Pointer to demodulator instance.
265 * \param skip : Minimum frequency step to take.
267 * \retval DRX_STS_OK: Succes.
268 * \retval DRX_STS_INVALID_ARG: Invalid frequency plan.
270 * Helper function for ctrl_scan_next() function.
271 * Compute next frequency & index in frequency plan.
272 * Check if scan is ready.
276 scan_prepare_next_scan(pdrx_demod_instance_t demod, s32 skip)
278 pdrx_common_attr_t common_attr = (pdrx_common_attr_t) (NULL);
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;
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;
294 /* Search next frequency to scan */
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;
301 /* and then as many steps necessary to exceed 'skip'
302 without exceeding end of the band */
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;
309 /* reset skip, in case we move to the next band later */
312 if (next_frequency > frequency_plan[table_index].last) {
313 /* reached end of this band */
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;
321 next_frequency = frequency_plan[table_index].first;
324 if (next_frequency > (tuner_max_frequency)) {
325 /* reached end of tuner range */
326 common_attr->scan_ready = true;
328 } while ((next_frequency < tuner_min_frequency) &&
329 (common_attr->scan_ready == false));
331 /* Store new values */
332 common_attr->scan_freq_plan_index = table_index;
333 common_attr->scan_next_frequency = next_frequency;
338 /*============================================================================*/
341 * \brief Default DTV scanning function.
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
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.
354 * scan_channel and get_next_channel will be NULL for INIT and STOP.
357 scan_function_default(void *scan_context,
358 drx_scan_command_t scan_command,
359 pdrx_channel_t scan_channel, bool *get_next_channel)
361 pdrx_demod_instance_t demod = NULL;
362 int status = DRX_STS_ERROR;
363 bool is_locked = false;
365 demod = (pdrx_demod_instance_t) scan_context;
367 if (scan_command != DRX_SCAN_COMMAND_NEXT) {
368 /* just return OK if not doing "scan next" */
372 *get_next_channel = false;
374 status = drx_ctrl(demod, DRX_CTRL_SET_CHANNEL, scan_channel);
375 if (status != DRX_STS_OK) {
379 status = scan_wait_for_lock(demod, &is_locked);
380 if (status != DRX_STS_OK) {
384 /* done with this channel, move to next one */
385 *get_next_channel = true;
387 if (is_locked == false) {
388 /* no channel found */
395 /*============================================================================*/
398 * \brief Initialize for channel scan.
399 * \param demod: Pointer to demodulator instance.
400 * \param scan_param: Pointer to scan parameters.
402 * \retval DRX_STS_OK: Initialized for scan.
403 * \retval DRX_STS_ERROR: No overlap between frequency plan and tuner
405 * \retval DRX_STS_INVALID_ARG: Wrong parameters.
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.
415 ctrl_scan_init(pdrx_demod_instance_t demod, p_drx_scan_param_t scan_param)
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;
423 void *scan_context = NULL;
425 common_attr = (pdrx_common_attr_t) demod->my_common_attr;
426 common_attr->scan_active = true;
428 /* invalidate a previous SCAN_INIT */
429 common_attr->scan_param = (p_drx_scan_param_t) (NULL);
430 common_attr->scan_next_frequency = 0;
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)
440 common_attr->scan_active = false;
441 return DRX_STS_INVALID_ARG;
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++) {
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;
456 /* Step must be positive and non-zero */
457 common_attr->scan_active = false;
458 return DRX_STS_INVALID_ARG;
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;
467 width = last_freq - first_freq;
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;
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;
484 n = (min_tuner_freq - first_freq) / step;
485 if (((min_tuner_freq -
486 first_freq) % step) != 0) {
489 min_freq = first_freq + n * step;
492 if (last_freq <= max_tuner_freq) {
493 max_freq = last_freq;
497 n = (last_freq - max_tuner_freq) / step;
499 max_tuner_freq) % step) != 0) {
502 max_freq = last_freq - n * step;
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);
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;
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;
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 */
534 scan_context = get_scan_context(demod, scan_context);
536 status = (*(get_scan_function(demod)))
537 (scan_context, DRX_SCAN_COMMAND_INIT, NULL, NULL);
539 common_attr->scan_active = false;
544 /*============================================================================*/
547 * \brief Stop scanning.
548 * \param demod: Pointer to demodulator instance.
550 * \retval DRX_STS_OK: Scan stopped.
551 * \retval DRX_STS_ERROR: Something went wrong.
552 * \retval DRX_STS_INVALID_ARG: Wrong parameters.
554 static int ctrl_scan_stop(pdrx_demod_instance_t demod)
556 int status = DRX_STS_ERROR;
557 pdrx_common_attr_t common_attr = (pdrx_common_attr_t) (NULL);
558 void *scan_context = NULL;
560 common_attr = (pdrx_common_attr_t) demod->my_common_attr;
561 common_attr->scan_active = true;
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;
570 /* Call default or device-specific scanning stop function */
571 scan_context = get_scan_context(demod, scan_context);
573 status = (*(get_scan_function(demod)))
574 (scan_context, DRX_SCAN_COMMAND_STOP, NULL, NULL);
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;
584 /*============================================================================*/
587 * \brief Scan for next channel.
588 * \param demod: Pointer to demodulator instance.
589 * \param scan_progress: Pointer to scan progress.
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
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.
601 * Progress indication will run from 0 upto DRX_SCAN_MAX_PROGRESS during scan.
604 static int ctrl_scan_next(pdrx_demod_instance_t demod, u16 *scan_progress)
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;
612 common_attr = (pdrx_common_attr_t) demod->my_common_attr;
614 /* Check scan parameters */
615 if (scan_progress == NULL) {
616 common_attr->scan_active = false;
617 return DRX_STS_INVALID_ARG;
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;
629 *scan_progress = (u16) (((common_attr->scan_channelsScanned) *
630 ((u32) (max_progress))) /
631 (common_attr->scan_max_channels));
634 num_tries = common_attr->scan_param->num_tries;
635 scan_ready = &(common_attr->scan_ready);
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;
644 /* Next channel to scan */
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;
665 /* Call default or device-specific scanning function */
666 scan_context = get_scan_context(demod, scan_context);
668 status = (*(get_scan_function(demod)))
669 (scan_context, DRX_SCAN_COMMAND_NEXT, &scan_channel,
672 /* Proceed to next channel if requested */
673 if (next_channel == true) {
674 int next_status = DRX_STS_ERROR;
677 if (status == DRX_STS_OK) {
678 /* a channel was found, so skip some frequency steps */
679 skip = common_attr->scan_param->skip;
681 next_status = scan_prepare_next_scan(demod, skip);
683 /* keep track of progress */
685 (u16) (((common_attr->scan_channelsScanned) *
686 ((u32) (max_progress))) /
687 (common_attr->scan_max_channels));
689 if (next_status != DRX_STS_OK) {
690 common_attr->scan_active = false;
691 return (next_status);
694 if (status != DRX_STS_BUSY) {
695 /* channel found or error */
696 common_attr->scan_active = false;
699 } /* for ( i = 0; i < ( ... num_tries); i++) */
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);
708 common_attr->scan_active = false;
713 #endif /* #ifndef DRX_EXCLUDE_SCAN */
715 /*============================================================================*/
718 * \brief Program tuner.
719 * \param demod: Pointer to demodulator instance.
720 * \param tunerChannel: Pointer to tuning parameters.
722 * \retval DRX_STS_OK: Tuner programmed successfully.
723 * \retval DRX_STS_ERROR: Something went wrong.
724 * \retval DRX_STS_INVALID_ARG: Wrong parameters.
726 * tunerChannel passes parameters to program the tuner,
727 * but also returns the actual RF and IF frequency from the tuner.
731 ctrl_program_tuner(pdrx_demod_instance_t demod, pdrx_channel_t channel)
733 pdrx_common_attr_t common_attr = (pdrx_common_attr_t) (NULL);
734 enum drx_standard standard = DRX_STANDARD_UNKNOWN;
736 int status = DRX_STS_ERROR;
737 s32 if_frequency = 0;
738 bool tuner_slow_mode = false;
740 /* can't tune without a tuner */
741 if (demod->my_tuner == NULL) {
742 return DRX_STS_INVALID_ARG;
745 common_attr = (pdrx_common_attr_t) demod->my_common_attr;
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;
752 if (DRX_ISATVSTD(standard)) {
753 tuner_mode |= TUNER_MODE_ANALOG;
754 } else { /* note: also for unknown standard */
756 tuner_mode |= TUNER_MODE_DIGITAL;
759 /* select tuner bandwidth */
760 switch (channel->bandwidth) {
761 case DRX_BANDWIDTH_6MHZ:
762 tuner_mode |= TUNER_MODE_6MHZ;
764 case DRX_BANDWIDTH_7MHZ:
765 tuner_mode |= TUNER_MODE_7MHZ;
767 case DRX_BANDWIDTH_8MHZ:
768 tuner_mode |= TUNER_MODE_8MHZ;
770 default: /* note: also for unknown bandwidth */
771 return DRX_STS_INVALID_ARG;
774 DRX_GET_TUNERSLOWMODE(demod, tuner_slow_mode);
776 /* select fast (switch) or slow (lock) tuner mode */
777 if (tuner_slow_mode) {
778 tuner_mode |= TUNER_MODE_LOCK;
780 tuner_mode |= TUNER_MODE_SWITCH;
783 if (common_attr->tuner_port_nr == 1) {
784 bool bridge_closed = true;
785 int status_bridge = DRX_STS_ERROR;
788 drx_ctrl(demod, DRX_CTRL_I2C_BRIDGE, &bridge_closed);
789 if (status_bridge != DRX_STS_OK) {
790 return status_bridge;
794 status = drxbsp_tuner_set_frequency(demod->my_tuner,
795 tuner_mode, channel->frequency);
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;
803 drx_ctrl(demod, DRX_CTRL_I2C_BRIDGE, &bridge_closed);
804 if (status_bridge != DRX_STS_OK) {
805 return status_bridge;
809 /* now check status of drxbsp_tuner_set_frequency */
810 if (status != DRX_STS_OK) {
814 /* get actual RF and IF frequencies from tuner */
815 status = drxbsp_tuner_get_frequency(demod->my_tuner,
817 &(channel->frequency),
819 if (status != DRX_STS_OK) {
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);
830 /*============================================================================*/
833 * \brief function to do a register dump.
834 * \param demod: Pointer to demodulator instance.
835 * \param registers: Registers to dump.
837 * \retval DRX_STS_OK: Dump executed successfully.
838 * \retval DRX_STS_ERROR: Something went wrong.
839 * \retval DRX_STS_INVALID_ARG: Wrong parameters.
842 int ctrl_dump_registers(pdrx_demod_instance_t demod,
843 p_drx_reg_dump_t registers)
847 if (registers == NULL) {
848 /* registers not supplied */
849 return DRX_STS_INVALID_ARG;
852 /* start dumping registers */
853 while (registers[i].address != 0) {
854 int status = DRX_STS_ERROR;
859 demod->my_access_funct->read_reg16func(demod->my_i2c_dev_addr,
860 registers[i].address,
865 if (status != DRX_STS_OK) {
867 depending on device ID, some HW blocks might not be available */
868 data |= ((u32) status) << 16;
870 registers[i].data = data;
874 /* all done, all OK (any errors are saved inside data) */
878 /*============================================================================*/
879 /*============================================================================*/
880 /*===Microcode related functions==============================================*/
881 /*============================================================================*/
882 /*============================================================================*/
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.
889 * This function takes care of the possible difference in endianness between the
890 * host and the data contained in the microcode image file.
893 static u16 u_code_read16(u8 *addr)
895 /* Works fo any host processor */
899 word = ((u16) addr[0]);
901 word |= ((u16) addr[1]);
906 /*============================================================================*/
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.
913 * This function takes care of the possible difference in endianness between the
914 * host and the data contained in the microcode image file.
917 static u32 u_code_read32(u8 *addr)
919 /* Works fo any host processor */
923 word = ((u16) addr[0]);
925 word |= ((u16) addr[1]);
927 word |= ((u16) addr[2]);
929 word |= ((u16) addr[3]);
934 /*============================================================================*/
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.
942 static u16 u_code_compute_crc(u8 *block_data, u16 nr_words)
949 while (i < nr_words) {
950 crc_word |= (u32) u_code_read16(block_data);
951 for (j = 0; j < 16; j++) {
954 crc_word ^= 0x80050000UL;
956 carry = crc_word & 0x80000000UL;
959 block_data += (sizeof(u16));
961 return ((u16) (crc_word >> 16));
964 /*============================================================================*/
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
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
985 ctrl_u_code(pdrx_demod_instance_t demod,
986 p_drxu_code_info_t mc_info, drxu_code_action_t action)
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);
995 dev_addr = demod->my_i2c_dev_addr;
997 /* Check arguments */
998 if ((mc_info == NULL) || (mc_info->mc_data == NULL)) {
999 return DRX_STS_INVALID_ARG;
1002 mc_data = mc_info->mc_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);
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;
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;
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);
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));
1055 mc_data += block_hdr.size * sizeof(u16);
1058 /* After scanning, validate the microcode.
1059 It is also valid if no validation control exists.
1061 rc = drx_ctrl(demod, DRX_CTRL_VALIDATE_UCODE, NULL);
1062 if (rc != DRX_STS_OK && rc != DRX_STS_FUNC_NOT_AVAILABLE) {
1066 /* Restore data pointer */
1067 mc_data = mc_info->mc_data + 2 * sizeof(u16);
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;
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);
1085 /* Check block header on:
1086 - data larger than 64Kb
1087 - if CRC enabled check CRC
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)))
1094 return DRX_STS_INVALID_ARG;
1097 mc_block_nr_bytes = block_hdr.size * ((u16) sizeof(u16));
1099 if (block_hdr.size != 0) {
1100 /* Perform the desired action */
1102 /*================================================================*/
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,
1113 return (DRX_STS_ERROR);
1118 /*================================================================*/
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;
1129 bytes_left_to_compare = mc_block_nr_bytes;
1130 curr_addr = block_hdr.addr;
1133 while (bytes_left_to_compare != 0) {
1134 if (bytes_left_to_compare >
1136 DRX_UCODE_MAX_BUF_SIZE)) {
1139 DRX_UCODE_MAX_BUF_SIZE);
1142 bytes_left_to_compare;
1145 if (demod->my_access_funct->
1146 read_block_func(dev_addr,
1154 return (DRX_STS_ERROR);
1158 drxbsp_hst_memcmp(curr_ptr,
1163 return DRX_STS_ERROR;
1168 (bytes_to_compare / 2));
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 ) */
1177 /*================================================================*/
1179 return DRX_STS_INVALID_ARG;
1182 } /* switch ( action ) */
1185 /* if (block_hdr.size != 0 ) */
1187 mc_data += mc_block_nr_bytes;
1189 } /* for( i = 0 ; i<mc_nr_of_blks ; i++ ) */
1194 /*============================================================================*/
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.
1201 * \retval DRX_STS_OK: Version information stored in version_list
1202 * \retval DRX_STS_INVALID_ARG: Invalid arguments.
1205 ctrl_version(pdrx_demod_instance_t demod, p_drx_version_list_t *version_list)
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);
1211 static drx_version_t drx_driver_core_version;
1212 static drx_version_list_t drx_driver_core_versionList;
1214 p_drx_version_list_t demod_version_list = (p_drx_version_list_t) (NULL);
1215 int return_status = DRX_STS_ERROR;
1217 /* Check arguments */
1218 if (version_list == NULL) {
1219 return DRX_STS_INVALID_ARG;
1222 /* Get version info list from demod */
1223 return_status = (*(demod->my_demod_funct->ctrl_func)) (demod,
1226 &demod_version_list);
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;
1236 drx_driver_core_versionList.version = &drx_driver_core_version;
1237 drx_driver_core_versionList.next = (p_drx_version_list_t) (NULL);
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;
1247 current_list_element->next = &drx_driver_core_versionList;
1249 *version_list = demod_version_list;
1251 /* Just return versioninfo from driver */
1252 *version_list = &drx_driver_core_versionList;
1258 /*============================================================================*/
1259 /*============================================================================*/
1260 /*== Exported functions ======================================================*/
1261 /*============================================================================*/
1262 /*============================================================================*/
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.
1270 * This function is obsolete, prototype available for backward compatability.
1274 int drx_init(pdrx_demod_instance_t demods[])
1279 /*============================================================================*/
1282 * \brief This function is obsolete.
1283 * \return int Return status.
1284 * \retval DRX_STS_OK: Terminated driver successful.
1286 * This function is obsolete, prototype available for backward compatability.
1295 /*============================================================================*/
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
1304 * \retval DRX_STS_INVALID_ARG: Demod instance has invalid content.
1308 int drx_open(pdrx_demod_instance_t demod)
1310 int status = DRX_STS_OK;
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);
1321 status = (*(demod->my_demod_funct->open_func)) (demod);
1323 if (status == DRX_STS_OK) {
1324 demod->my_common_attr->is_opened = true;
1330 /*============================================================================*/
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
1339 * \retval DRX_STS_INVALID_ARG: Demod instance has invalid content.
1341 * Free resources occupied by device instance.
1342 * Put device into sleep mode.
1345 int drx_close(pdrx_demod_instance_t demod)
1347 int status = DRX_STS_OK;
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;
1358 status = (*(demod->my_demod_funct->close_func)) (demod);
1360 DRX_SET_ISOPENED(demod, false);
1365 /*============================================================================*/
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
1376 * \retval DRX_STS_INVALID_ARG: Demod instance or ctrl_data has invalid
1378 * \retval DRX_STS_FUNC_NOT_AVAILABLE: Specified control function is not
1381 * Data needed or returned by the control function is stored in ctrl_data.
1386 drx_ctrl(pdrx_demod_instance_t demod, u32 ctrl, void *ctrl_data)
1388 int status = DRX_STS_ERROR;
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)
1395 return (DRX_STS_INVALID_ARG);
1398 if (((demod->my_common_attr->is_opened == false) &&
1399 (ctrl != DRX_CTRL_PROBE_DEVICE) && (ctrl != DRX_CTRL_VERSION))
1401 return (DRX_STS_INVALID_ARG);
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)
1410 return DRX_STS_FUNC_NOT_AVAILABLE;
1413 /* Fixed control functions */
1415 /*======================================================================*/
1421 /*======================================================================*/
1422 case DRX_CTRL_VERSION:
1423 return ctrl_version(demod, (p_drx_version_list_t *) ctrl_data);
1426 /*======================================================================*/
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 */
1438 /*===================================================================*/
1439 case DRX_CTRL_LOAD_UCODE:
1440 return ctrl_u_code(demod,
1441 (p_drxu_code_info_t) ctrl_data,
1445 /*===================================================================*/
1446 case DRX_CTRL_VERIFY_UCODE:
1448 return ctrl_u_code(demod,
1449 (p_drxu_code_info_t) ctrl_data,
1454 #ifndef DRX_EXCLUDE_SCAN
1455 /*===================================================================*/
1456 case DRX_CTRL_SCAN_INIT:
1458 return ctrl_scan_init(demod,
1459 (p_drx_scan_param_t) ctrl_data);
1463 /*===================================================================*/
1464 case DRX_CTRL_SCAN_NEXT:
1466 return ctrl_scan_next(demod, (u16 *) ctrl_data);
1470 /*===================================================================*/
1471 case DRX_CTRL_SCAN_STOP:
1473 return ctrl_scan_stop(demod);
1476 #endif /* #ifndef DRX_EXCLUDE_SCAN */
1478 /*===================================================================*/
1479 case DRX_CTRL_PROGRAM_TUNER:
1481 return ctrl_program_tuner(demod,
1487 /*===================================================================*/
1488 case DRX_CTRL_DUMP_REGISTERS:
1490 return ctrl_dump_registers(demod,
1496 /*===================================================================*/
1498 return DRX_STS_FUNC_NOT_AVAILABLE;
1507 /*============================================================================*/