Commit | Line | Data |
---|---|---|
ca3355a9 DH |
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 | ||
38b2df95 DH |
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 | * | |
38b2df95 DH |
36 | */ |
37 | ||
38 | /*------------------------------------------------------------------------------ | |
39 | INCLUDE FILES | |
40 | ------------------------------------------------------------------------------*/ | |
41 | #include "drx_driver.h" | |
38b2df95 DH |
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 | |
43a431e4 | 62 | #define DRX_UCODE_MAGIC_WORD ((((u16)'H')<<8)+((u16)'L')) |
38b2df95 DH |
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 { | |
43a431e4 | 121 | u32 addr; |
443f18d0 | 122 | /**< Destination address of the data in this block */ |
43a431e4 | 123 | u16 size; |
443f18d0 | 124 | /**< Size of the block data following this header counted in |
38b2df95 | 125 | 16 bits words */ |
43a431e4 | 126 | u16 flags; |
443f18d0 | 127 | /**< Flags for this data block: |
38b2df95 DH |
128 | - bit[0]= CRC on/off |
129 | - bit[1]= compression on/off | |
130 | - bit[15..2]=reserved */ | |
43a431e4 | 131 | u16 CRC;/**< CRC value of the data block, only valid if CRC flag is |
38b2df95 DH |
132 | set. */ |
133 | } DRXUCodeBlockHdr_t, *pDRXUCodeBlockHdr_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 DRXStatus_t | |
443f18d0 MCC |
149 | ScanFunctionDefault(void *scanContext, |
150 | DRXScanCommand_t scanCommand, | |
73f7065b | 151 | pDRXChannel_t scanChannel, bool * getNextChannel); |
38b2df95 DH |
152 | |
153 | /** | |
154 | * \brief Get pointer to scanning function. | |
155 | * \param demod: Pointer to demodulator instance. | |
156 | * \return DRXScanFunc_t. | |
157 | */ | |
443f18d0 | 158 | static DRXScanFunc_t GetScanFunction(pDRXDemodInstance_t demod) |
38b2df95 | 159 | { |
443f18d0 MCC |
160 | pDRXCommonAttr_t commonAttr = (pDRXCommonAttr_t) (NULL); |
161 | DRXScanFunc_t scanFunc = (DRXScanFunc_t) (NULL); | |
162 | ||
163 | /* get scan function from common attributes */ | |
164 | commonAttr = (pDRXCommonAttr_t) demod->myCommonAttr; | |
165 | scanFunc = commonAttr->scanFunction; | |
166 | ||
167 | if (scanFunc != NULL) { | |
168 | /* return device-specific scan function if it's not NULL */ | |
169 | return scanFunc; | |
170 | } | |
171 | /* otherwise return default scan function in core driver */ | |
172 | return &ScanFunctionDefault; | |
38b2df95 DH |
173 | } |
174 | ||
175 | /** | |
176 | * \brief Get Context pointer. | |
177 | * \param demod: Pointer to demodulator instance. | |
178 | * \param scanContext: Context Pointer. | |
179 | * \return DRXScanFunc_t. | |
180 | */ | |
443f18d0 | 181 | void *GetScanContext(pDRXDemodInstance_t demod, void *scanContext) |
38b2df95 | 182 | { |
443f18d0 | 183 | pDRXCommonAttr_t commonAttr = (pDRXCommonAttr_t) (NULL); |
38b2df95 | 184 | |
443f18d0 MCC |
185 | /* get scan function from common attributes */ |
186 | commonAttr = (pDRXCommonAttr_t) demod->myCommonAttr; | |
187 | scanContext = commonAttr->scanContext; | |
38b2df95 | 188 | |
443f18d0 MCC |
189 | if (scanContext == NULL) { |
190 | scanContext = (void *)demod; | |
191 | } | |
38b2df95 | 192 | |
443f18d0 | 193 | return scanContext; |
38b2df95 DH |
194 | } |
195 | ||
196 | /** | |
197 | * \brief Wait for lock while scanning. | |
198 | * \param demod: Pointer to demodulator instance. | |
199 | * \param lockStat: Pointer to bool indicating if end result is lock or not. | |
200 | * \return DRXStatus_t. | |
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 | */ | |
73f7065b | 214 | static DRXStatus_t ScanWaitForLock(pDRXDemodInstance_t demod, bool * isLocked) |
38b2df95 | 215 | { |
73f7065b | 216 | bool doneWaiting = false; |
443f18d0 MCC |
217 | DRXLockStatus_t lockState = DRX_NOT_LOCKED; |
218 | DRXLockStatus_t desiredLockState = DRX_NOT_LOCKED; | |
43a431e4 MCC |
219 | u32 timeoutValue = 0; |
220 | u32 startTimeLockStage = 0; | |
221 | u32 currentTime = 0; | |
222 | u32 timerValue = 0; | |
443f18d0 | 223 | |
73f7065b | 224 | *isLocked = false; |
43a431e4 | 225 | timeoutValue = (u32) demod->myCommonAttr->scanDemodLockTimeout; |
443f18d0 MCC |
226 | desiredLockState = demod->myCommonAttr->scanDesiredLock; |
227 | startTimeLockStage = DRXBSP_HST_Clock(); | |
228 | ||
229 | /* Start polling loop, checking for lock & timeout */ | |
73f7065b | 230 | while (doneWaiting == false) { |
443f18d0 MCC |
231 | |
232 | if (DRX_Ctrl(demod, DRX_CTRL_LOCK_STATUS, &lockState) != | |
233 | DRX_STS_OK) { | |
234 | return DRX_STS_ERROR; | |
235 | } | |
236 | currentTime = DRXBSP_HST_Clock(); | |
237 | ||
238 | timerValue = currentTime - startTimeLockStage; | |
239 | if (lockState >= desiredLockState) { | |
73f7065b MCC |
240 | *isLocked = true; |
241 | doneWaiting = true; | |
443f18d0 MCC |
242 | } /* if ( lockState >= desiredLockState ) .. */ |
243 | else if (lockState == DRX_NEVER_LOCK) { | |
73f7065b | 244 | doneWaiting = true; |
443f18d0 MCC |
245 | } /* if ( lockState == DRX_NEVER_LOCK ) .. */ |
246 | else if (timerValue > timeoutValue) { | |
247 | /* lockState == DRX_NOT_LOCKED and timeout */ | |
73f7065b | 248 | doneWaiting = true; |
443f18d0 MCC |
249 | } else { |
250 | if (DRXBSP_HST_Sleep(10) != DRX_STS_OK) { | |
251 | return DRX_STS_ERROR; | |
252 | } | |
253 | } /* if ( timerValue > timeoutValue ) .. */ | |
254 | ||
255 | } /* while */ | |
256 | ||
257 | return DRX_STS_OK; | |
38b2df95 DH |
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 DRXStatus_t. | |
267 | * \retval DRX_STS_OK: Succes. | |
268 | * \retval DRX_STS_INVALID_ARG: Invalid frequency plan. | |
269 | * | |
270 | * Helper function for CtrlScanNext() function. | |
271 | * Compute next frequency & index in frequency plan. | |
272 | * Check if scan is ready. | |
273 | * | |
274 | */ | |
275 | static DRXStatus_t | |
73f7065b | 276 | ScanPrepareNextScan(pDRXDemodInstance_t demod, s32 skip) |
38b2df95 | 277 | { |
443f18d0 | 278 | pDRXCommonAttr_t commonAttr = (pDRXCommonAttr_t) (NULL); |
43a431e4 MCC |
279 | u16 tableIndex = 0; |
280 | u16 frequencyPlanSize = 0; | |
443f18d0 | 281 | pDRXFrequencyPlan_t frequencyPlan = (pDRXFrequencyPlan_t) (NULL); |
73f7065b MCC |
282 | s32 nextFrequency = 0; |
283 | s32 tunerMinFrequency = 0; | |
284 | s32 tunerMaxFrequency = 0; | |
443f18d0 MCC |
285 | |
286 | commonAttr = (pDRXCommonAttr_t) demod->myCommonAttr; | |
287 | tableIndex = commonAttr->scanFreqPlanIndex; | |
288 | frequencyPlan = commonAttr->scanParam->frequencyPlan; | |
289 | nextFrequency = commonAttr->scanNextFrequency; | |
290 | tunerMinFrequency = commonAttr->tunerMinFreqRF; | |
291 | tunerMaxFrequency = commonAttr->tunerMaxFreqRF; | |
292 | ||
293 | do { | |
294 | /* Search next frequency to scan */ | |
295 | ||
296 | /* always take at least one step */ | |
297 | (commonAttr->scanChannelsScanned)++; | |
298 | nextFrequency += frequencyPlan[tableIndex].step; | |
299 | skip -= frequencyPlan[tableIndex].step; | |
300 | ||
301 | /* and then as many steps necessary to exceed 'skip' | |
302 | without exceeding end of the band */ | |
303 | while ((skip > 0) && | |
304 | (nextFrequency <= frequencyPlan[tableIndex].last)) { | |
305 | (commonAttr->scanChannelsScanned)++; | |
306 | nextFrequency += frequencyPlan[tableIndex].step; | |
307 | skip -= frequencyPlan[tableIndex].step; | |
308 | } | |
309 | /* reset skip, in case we move to the next band later */ | |
310 | skip = 0; | |
311 | ||
312 | if (nextFrequency > frequencyPlan[tableIndex].last) { | |
313 | /* reached end of this band */ | |
314 | tableIndex++; | |
315 | frequencyPlanSize = | |
316 | commonAttr->scanParam->frequencyPlanSize; | |
317 | if (tableIndex >= frequencyPlanSize) { | |
318 | /* reached end of frequency plan */ | |
73f7065b | 319 | commonAttr->scanReady = true; |
443f18d0 MCC |
320 | } else { |
321 | nextFrequency = frequencyPlan[tableIndex].first; | |
322 | } | |
323 | } | |
324 | if (nextFrequency > (tunerMaxFrequency)) { | |
325 | /* reached end of tuner range */ | |
73f7065b | 326 | commonAttr->scanReady = true; |
443f18d0 MCC |
327 | } |
328 | } while ((nextFrequency < tunerMinFrequency) && | |
73f7065b | 329 | (commonAttr->scanReady == false)); |
443f18d0 MCC |
330 | |
331 | /* Store new values */ | |
332 | commonAttr->scanFreqPlanIndex = tableIndex; | |
333 | commonAttr->scanNextFrequency = nextFrequency; | |
334 | ||
335 | return DRX_STS_OK; | |
38b2df95 DH |
336 | } |
337 | ||
338 | /*============================================================================*/ | |
339 | ||
340 | /** | |
341 | * \brief Default DTV scanning function. | |
342 | * | |
343 | * \param demod: Pointer to demodulator instance. | |
344 | * \param scanCommand: Scanning command: INIT, NEXT or STOP. | |
345 | * \param scanChannel: Channel to check: frequency and bandwidth, others AUTO | |
73f7065b | 346 | * \param getNextChannel: Return true if next frequency is desired at next call |
38b2df95 DH |
347 | * |
348 | * \return DRXStatus_t. | |
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 | * scanChannel and getNextChannel will be NULL for INIT and STOP. | |
355 | */ | |
356 | static DRXStatus_t | |
443f18d0 MCC |
357 | ScanFunctionDefault(void *scanContext, |
358 | DRXScanCommand_t scanCommand, | |
73f7065b | 359 | pDRXChannel_t scanChannel, bool * getNextChannel) |
38b2df95 | 360 | { |
443f18d0 MCC |
361 | pDRXDemodInstance_t demod = NULL; |
362 | DRXStatus_t status = DRX_STS_ERROR; | |
73f7065b | 363 | bool isLocked = false; |
443f18d0 MCC |
364 | |
365 | demod = (pDRXDemodInstance_t) scanContext; | |
366 | ||
367 | if (scanCommand != DRX_SCAN_COMMAND_NEXT) { | |
368 | /* just return OK if not doing "scan next" */ | |
369 | return DRX_STS_OK; | |
370 | } | |
371 | ||
73f7065b | 372 | *getNextChannel = false; |
443f18d0 MCC |
373 | |
374 | status = DRX_Ctrl(demod, DRX_CTRL_SET_CHANNEL, scanChannel); | |
375 | if (status != DRX_STS_OK) { | |
376 | return (status); | |
377 | } | |
378 | ||
379 | status = ScanWaitForLock(demod, &isLocked); | |
380 | if (status != DRX_STS_OK) { | |
381 | return status; | |
382 | } | |
383 | ||
384 | /* done with this channel, move to next one */ | |
73f7065b | 385 | *getNextChannel = true; |
443f18d0 | 386 | |
73f7065b | 387 | if (isLocked == false) { |
443f18d0 MCC |
388 | /* no channel found */ |
389 | return DRX_STS_BUSY; | |
390 | } | |
391 | /* channel found */ | |
392 | return DRX_STS_OK; | |
38b2df95 DH |
393 | } |
394 | ||
395 | /*============================================================================*/ | |
396 | ||
397 | /** | |
398 | * \brief Initialize for channel scan. | |
399 | * \param demod: Pointer to demodulator instance. | |
400 | * \param scanParam: Pointer to scan parameters. | |
401 | * \return DRXStatus_t. | |
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 DRXStatus_t | |
443f18d0 | 415 | CtrlScanInit(pDRXDemodInstance_t demod, pDRXScanParam_t scanParam) |
38b2df95 | 416 | { |
443f18d0 MCC |
417 | DRXStatus_t status = DRX_STS_ERROR; |
418 | pDRXCommonAttr_t commonAttr = (pDRXCommonAttr_t) (NULL); | |
73f7065b MCC |
419 | s32 maxTunerFreq = 0; |
420 | s32 minTunerFreq = 0; | |
43a431e4 MCC |
421 | u16 nrChannelsInPlan = 0; |
422 | u16 i = 0; | |
443f18d0 MCC |
423 | void *scanContext = NULL; |
424 | ||
425 | commonAttr = (pDRXCommonAttr_t) demod->myCommonAttr; | |
73f7065b | 426 | commonAttr->scanActive = true; |
443f18d0 MCC |
427 | |
428 | /* invalidate a previous SCAN_INIT */ | |
429 | commonAttr->scanParam = (pDRXScanParam_t) (NULL); | |
430 | commonAttr->scanNextFrequency = 0; | |
431 | ||
432 | /* Check parameters */ | |
433 | if (((demod->myTuner == NULL) && | |
434 | (scanParam->numTries != 1)) || | |
435 | (scanParam == NULL) || | |
436 | (scanParam->numTries == 0) || | |
437 | (scanParam->frequencyPlan == NULL) || | |
438 | (scanParam->frequencyPlanSize == 0) | |
439 | ) { | |
73f7065b | 440 | commonAttr->scanActive = false; |
443f18d0 MCC |
441 | return DRX_STS_INVALID_ARG; |
442 | } | |
443 | ||
444 | /* Check frequency plan contents */ | |
445 | maxTunerFreq = commonAttr->tunerMaxFreqRF; | |
446 | minTunerFreq = commonAttr->tunerMinFreqRF; | |
447 | for (i = 0; i < (scanParam->frequencyPlanSize); i++) { | |
73f7065b MCC |
448 | s32 width = 0; |
449 | s32 step = scanParam->frequencyPlan[i].step; | |
450 | s32 firstFreq = scanParam->frequencyPlan[i].first; | |
451 | s32 lastFreq = scanParam->frequencyPlan[i].last; | |
452 | s32 minFreq = 0; | |
453 | s32 maxFreq = 0; | |
443f18d0 MCC |
454 | |
455 | if (step <= 0) { | |
456 | /* Step must be positive and non-zero */ | |
73f7065b | 457 | commonAttr->scanActive = false; |
443f18d0 MCC |
458 | return DRX_STS_INVALID_ARG; |
459 | } | |
460 | ||
461 | if (firstFreq > lastFreq) { | |
462 | /* First center frequency is higher than last center frequency */ | |
73f7065b | 463 | commonAttr->scanActive = false; |
443f18d0 MCC |
464 | return DRX_STS_INVALID_ARG; |
465 | } | |
466 | ||
467 | width = lastFreq - firstFreq; | |
468 | ||
469 | if ((width % step) != 0) { | |
470 | /* Difference between last and first center frequency is not | |
471 | an integer number of steps */ | |
73f7065b | 472 | commonAttr->scanActive = false; |
443f18d0 MCC |
473 | return DRX_STS_INVALID_ARG; |
474 | } | |
475 | ||
476 | /* Check if frequency plan entry intersects with tuner range */ | |
477 | if (lastFreq >= minTunerFreq) { | |
478 | if (firstFreq <= maxTunerFreq) { | |
479 | if (firstFreq >= minTunerFreq) { | |
480 | minFreq = firstFreq; | |
481 | } else { | |
73f7065b | 482 | s32 n = 0; |
443f18d0 MCC |
483 | |
484 | n = (minTunerFreq - firstFreq) / step; | |
485 | if (((minTunerFreq - | |
486 | firstFreq) % step) != 0) { | |
487 | n++; | |
488 | } | |
489 | minFreq = firstFreq + n * step; | |
490 | } | |
491 | ||
492 | if (lastFreq <= maxTunerFreq) { | |
493 | maxFreq = lastFreq; | |
494 | } else { | |
73f7065b | 495 | s32 n = 0; |
443f18d0 MCC |
496 | |
497 | n = (lastFreq - maxTunerFreq) / step; | |
498 | if (((lastFreq - | |
499 | maxTunerFreq) % step) != 0) { | |
500 | n++; | |
501 | } | |
502 | maxFreq = lastFreq - n * step; | |
503 | } | |
504 | } | |
505 | } | |
506 | ||
507 | /* Keep track of total number of channels within tuner range | |
508 | in this frequency plan. */ | |
509 | if ((minFreq != 0) && (maxFreq != 0)) { | |
510 | nrChannelsInPlan += | |
43a431e4 | 511 | (u16) (((maxFreq - minFreq) / step) + 1); |
443f18d0 MCC |
512 | |
513 | /* Determine first frequency (within tuner range) to scan */ | |
514 | if (commonAttr->scanNextFrequency == 0) { | |
515 | commonAttr->scanNextFrequency = minFreq; | |
516 | commonAttr->scanFreqPlanIndex = i; | |
517 | } | |
518 | } | |
519 | ||
520 | } /* for ( ... ) */ | |
521 | ||
522 | if (nrChannelsInPlan == 0) { | |
523 | /* Tuner range and frequency plan ranges do not overlap */ | |
73f7065b | 524 | commonAttr->scanActive = false; |
443f18d0 MCC |
525 | return DRX_STS_ERROR; |
526 | } | |
527 | ||
528 | /* Store parameters */ | |
73f7065b | 529 | commonAttr->scanReady = false; |
443f18d0 MCC |
530 | commonAttr->scanMaxChannels = nrChannelsInPlan; |
531 | commonAttr->scanChannelsScanned = 0; | |
532 | commonAttr->scanParam = scanParam; /* SCAN_NEXT is now allowed */ | |
533 | ||
534 | scanContext = GetScanContext(demod, scanContext); | |
535 | ||
536 | status = (*(GetScanFunction(demod))) | |
537 | (scanContext, DRX_SCAN_COMMAND_INIT, NULL, NULL); | |
538 | ||
73f7065b | 539 | commonAttr->scanActive = false; |
443f18d0 MCC |
540 | |
541 | return DRX_STS_OK; | |
38b2df95 DH |
542 | } |
543 | ||
544 | /*============================================================================*/ | |
545 | ||
546 | /** | |
547 | * \brief Stop scanning. | |
548 | * \param demod: Pointer to demodulator instance. | |
549 | * \return DRXStatus_t. | |
550 | * \retval DRX_STS_OK: Scan stopped. | |
551 | * \retval DRX_STS_ERROR: Something went wrong. | |
552 | * \retval DRX_STS_INVALID_ARG: Wrong parameters. | |
553 | */ | |
443f18d0 | 554 | static DRXStatus_t CtrlScanStop(pDRXDemodInstance_t demod) |
38b2df95 | 555 | { |
443f18d0 MCC |
556 | DRXStatus_t status = DRX_STS_ERROR; |
557 | pDRXCommonAttr_t commonAttr = (pDRXCommonAttr_t) (NULL); | |
558 | void *scanContext = NULL; | |
38b2df95 | 559 | |
443f18d0 | 560 | commonAttr = (pDRXCommonAttr_t) demod->myCommonAttr; |
73f7065b | 561 | commonAttr->scanActive = true; |
38b2df95 | 562 | |
443f18d0 MCC |
563 | if ((commonAttr->scanParam == NULL) || |
564 | (commonAttr->scanMaxChannels == 0)) { | |
565 | /* Scan was not running, just return OK */ | |
73f7065b | 566 | commonAttr->scanActive = false; |
443f18d0 MCC |
567 | return DRX_STS_OK; |
568 | } | |
38b2df95 | 569 | |
443f18d0 MCC |
570 | /* Call default or device-specific scanning stop function */ |
571 | scanContext = GetScanContext(demod, scanContext); | |
38b2df95 | 572 | |
443f18d0 MCC |
573 | status = (*(GetScanFunction(demod))) |
574 | (scanContext, DRX_SCAN_COMMAND_STOP, NULL, NULL); | |
38b2df95 | 575 | |
443f18d0 MCC |
576 | /* All done, invalidate scan-init */ |
577 | commonAttr->scanParam = NULL; | |
578 | commonAttr->scanMaxChannels = 0; | |
73f7065b | 579 | commonAttr->scanActive = false; |
38b2df95 | 580 | |
443f18d0 | 581 | return status; |
38b2df95 DH |
582 | } |
583 | ||
584 | /*============================================================================*/ | |
585 | ||
586 | /** | |
587 | * \brief Scan for next channel. | |
588 | * \param demod: Pointer to demodulator instance. | |
589 | * \param scanProgress: Pointer to scan progress. | |
590 | * \return DRXStatus_t. | |
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 | * numTries 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 scanProgress may be NULL. | |
600 | * | |
601 | * Progress indication will run from 0 upto DRX_SCAN_MAX_PROGRESS during scan. | |
602 | * | |
603 | */ | |
43a431e4 | 604 | static DRXStatus_t CtrlScanNext(pDRXDemodInstance_t demod, u16 *scanProgress) |
38b2df95 | 605 | { |
443f18d0 | 606 | pDRXCommonAttr_t commonAttr = (pDRXCommonAttr_t) (NULL); |
73f7065b | 607 | bool * scanReady = (bool *) (NULL); |
43a431e4 MCC |
608 | u16 maxProgress = DRX_SCAN_MAX_PROGRESS; |
609 | u32 numTries = 0; | |
610 | u32 i = 0; | |
443f18d0 MCC |
611 | |
612 | commonAttr = (pDRXCommonAttr_t) demod->myCommonAttr; | |
613 | ||
614 | /* Check scan parameters */ | |
615 | if (scanProgress == NULL) { | |
73f7065b | 616 | commonAttr->scanActive = false; |
443f18d0 MCC |
617 | return DRX_STS_INVALID_ARG; |
618 | } | |
619 | ||
620 | *scanProgress = 0; | |
73f7065b | 621 | commonAttr->scanActive = true; |
443f18d0 MCC |
622 | if ((commonAttr->scanParam == NULL) || |
623 | (commonAttr->scanMaxChannels == 0)) { | |
624 | /* CtrlScanInit() was not called succesfully before CtrlScanNext() */ | |
73f7065b | 625 | commonAttr->scanActive = false; |
443f18d0 MCC |
626 | return DRX_STS_ERROR; |
627 | } | |
628 | ||
43a431e4 MCC |
629 | *scanProgress = (u16) (((commonAttr->scanChannelsScanned) * |
630 | ((u32) (maxProgress))) / | |
443f18d0 MCC |
631 | (commonAttr->scanMaxChannels)); |
632 | ||
633 | /* Scan */ | |
634 | numTries = commonAttr->scanParam->numTries; | |
635 | scanReady = &(commonAttr->scanReady); | |
636 | ||
73f7065b | 637 | for (i = 0; ((i < numTries) && ((*scanReady) == false)); i++) { |
443f18d0 MCC |
638 | DRXChannel_t scanChannel = { 0 }; |
639 | DRXStatus_t status = DRX_STS_ERROR; | |
640 | pDRXFrequencyPlan_t freqPlan = (pDRXFrequencyPlan_t) (NULL); | |
73f7065b | 641 | bool nextChannel = false; |
443f18d0 MCC |
642 | void *scanContext = NULL; |
643 | ||
644 | /* Next channel to scan */ | |
645 | freqPlan = | |
646 | &(commonAttr->scanParam-> | |
647 | frequencyPlan[commonAttr->scanFreqPlanIndex]); | |
648 | scanChannel.frequency = commonAttr->scanNextFrequency; | |
649 | scanChannel.bandwidth = freqPlan->bandwidth; | |
650 | scanChannel.mirror = DRX_MIRROR_AUTO; | |
651 | scanChannel.constellation = DRX_CONSTELLATION_AUTO; | |
652 | scanChannel.hierarchy = DRX_HIERARCHY_AUTO; | |
653 | scanChannel.priority = DRX_PRIORITY_HIGH; | |
654 | scanChannel.coderate = DRX_CODERATE_AUTO; | |
655 | scanChannel.guard = DRX_GUARD_AUTO; | |
656 | scanChannel.fftmode = DRX_FFTMODE_AUTO; | |
657 | scanChannel.classification = DRX_CLASSIFICATION_AUTO; | |
658 | scanChannel.symbolrate = 0; | |
659 | scanChannel.interleavemode = DRX_INTERLEAVEMODE_AUTO; | |
660 | scanChannel.ldpc = DRX_LDPC_AUTO; | |
661 | scanChannel.carrier = DRX_CARRIER_AUTO; | |
662 | scanChannel.framemode = DRX_FRAMEMODE_AUTO; | |
663 | scanChannel.pilot = DRX_PILOT_AUTO; | |
664 | ||
665 | /* Call default or device-specific scanning function */ | |
666 | scanContext = GetScanContext(demod, scanContext); | |
667 | ||
668 | status = (*(GetScanFunction(demod))) | |
669 | (scanContext, DRX_SCAN_COMMAND_NEXT, &scanChannel, | |
670 | &nextChannel); | |
671 | ||
672 | /* Proceed to next channel if requested */ | |
73f7065b | 673 | if (nextChannel == true) { |
443f18d0 | 674 | DRXStatus_t nextStatus = DRX_STS_ERROR; |
73f7065b | 675 | s32 skip = 0; |
443f18d0 MCC |
676 | |
677 | if (status == DRX_STS_OK) { | |
678 | /* a channel was found, so skip some frequency steps */ | |
679 | skip = commonAttr->scanParam->skip; | |
680 | } | |
681 | nextStatus = ScanPrepareNextScan(demod, skip); | |
682 | ||
683 | /* keep track of progress */ | |
684 | *scanProgress = | |
43a431e4 MCC |
685 | (u16) (((commonAttr->scanChannelsScanned) * |
686 | ((u32) (maxProgress))) / | |
443f18d0 MCC |
687 | (commonAttr->scanMaxChannels)); |
688 | ||
689 | if (nextStatus != DRX_STS_OK) { | |
73f7065b | 690 | commonAttr->scanActive = false; |
443f18d0 MCC |
691 | return (nextStatus); |
692 | } | |
693 | } | |
694 | if (status != DRX_STS_BUSY) { | |
695 | /* channel found or error */ | |
73f7065b | 696 | commonAttr->scanActive = false; |
443f18d0 MCC |
697 | return status; |
698 | } | |
699 | } /* for ( i = 0; i < ( ... numTries); i++) */ | |
700 | ||
73f7065b | 701 | if ((*scanReady) == true) { |
443f18d0 MCC |
702 | /* End of scan reached: call stop-scan, ignore any error */ |
703 | CtrlScanStop(demod); | |
73f7065b | 704 | commonAttr->scanActive = false; |
443f18d0 MCC |
705 | return (DRX_STS_READY); |
706 | } | |
707 | ||
73f7065b | 708 | commonAttr->scanActive = false; |
443f18d0 MCC |
709 | |
710 | return DRX_STS_BUSY; | |
38b2df95 DH |
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 DRXStatus_t. | |
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 DRXStatus_t | |
443f18d0 | 731 | CtrlProgramTuner(pDRXDemodInstance_t demod, pDRXChannel_t channel) |
38b2df95 | 732 | { |
443f18d0 MCC |
733 | pDRXCommonAttr_t commonAttr = (pDRXCommonAttr_t) (NULL); |
734 | DRXStandard_t standard = DRX_STANDARD_UNKNOWN; | |
735 | TUNERMode_t tunerMode = 0; | |
736 | DRXStatus_t status = DRX_STS_ERROR; | |
73f7065b MCC |
737 | s32 ifFrequency = 0; |
738 | bool tunerSlowMode = false; | |
443f18d0 MCC |
739 | |
740 | /* can't tune without a tuner */ | |
741 | if (demod->myTuner == NULL) { | |
742 | return DRX_STS_INVALID_ARG; | |
743 | } | |
744 | ||
745 | commonAttr = (pDRXCommonAttr_t) demod->myCommonAttr; | |
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 | tunerMode |= TUNER_MODE_ANALOG; | |
754 | } else { /* note: also for unknown standard */ | |
755 | ||
756 | tunerMode |= TUNER_MODE_DIGITAL; | |
757 | } | |
758 | ||
759 | /* select tuner bandwidth */ | |
760 | switch (channel->bandwidth) { | |
761 | case DRX_BANDWIDTH_6MHZ: | |
762 | tunerMode |= TUNER_MODE_6MHZ; | |
763 | break; | |
764 | case DRX_BANDWIDTH_7MHZ: | |
765 | tunerMode |= TUNER_MODE_7MHZ; | |
766 | break; | |
767 | case DRX_BANDWIDTH_8MHZ: | |
768 | tunerMode |= 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, tunerSlowMode); | |
775 | ||
776 | /* select fast (switch) or slow (lock) tuner mode */ | |
777 | if (tunerSlowMode) { | |
778 | tunerMode |= TUNER_MODE_LOCK; | |
779 | } else { | |
780 | tunerMode |= TUNER_MODE_SWITCH; | |
781 | } | |
782 | ||
783 | if (commonAttr->tunerPortNr == 1) { | |
73f7065b | 784 | bool bridgeClosed = true; |
443f18d0 MCC |
785 | DRXStatus_t statusBridge = DRX_STS_ERROR; |
786 | ||
787 | statusBridge = | |
788 | DRX_Ctrl(demod, DRX_CTRL_I2C_BRIDGE, &bridgeClosed); | |
789 | if (statusBridge != DRX_STS_OK) { | |
790 | return statusBridge; | |
791 | } | |
792 | } | |
793 | ||
794 | status = DRXBSP_TUNER_SetFrequency(demod->myTuner, | |
795 | tunerMode, channel->frequency); | |
796 | ||
797 | /* attempt restoring bridge before checking status of SetFrequency */ | |
798 | if (commonAttr->tunerPortNr == 1) { | |
73f7065b | 799 | bool bridgeClosed = false; |
443f18d0 MCC |
800 | DRXStatus_t statusBridge = DRX_STS_ERROR; |
801 | ||
802 | statusBridge = | |
803 | DRX_Ctrl(demod, DRX_CTRL_I2C_BRIDGE, &bridgeClosed); | |
804 | if (statusBridge != DRX_STS_OK) { | |
805 | return statusBridge; | |
806 | } | |
807 | } | |
808 | ||
809 | /* now check status of DRXBSP_TUNER_SetFrequency */ | |
810 | if (status != DRX_STS_OK) { | |
811 | return status; | |
812 | } | |
813 | ||
814 | /* get actual RF and IF frequencies from tuner */ | |
815 | status = DRXBSP_TUNER_GetFrequency(demod->myTuner, | |
816 | tunerMode, | |
817 | &(channel->frequency), | |
818 | &(ifFrequency)); | |
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, ifFrequency); | |
826 | ||
827 | return DRX_STS_OK; | |
38b2df95 DH |
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 DRXStatus_t. | |
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 | */ | |
443f18d0 MCC |
842 | DRXStatus_t CtrlDumpRegisters(pDRXDemodInstance_t demod, |
843 | pDRXRegDump_t registers) | |
38b2df95 | 844 | { |
43a431e4 | 845 | u16 i = 0; |
443f18d0 MCC |
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 | DRXStatus_t status = DRX_STS_ERROR; | |
43a431e4 MCC |
855 | u16 value = 0; |
856 | u32 data = 0; | |
443f18d0 MCC |
857 | |
858 | status = | |
859 | demod->myAccessFunct->readReg16Func(demod->myI2CDevAddr, | |
860 | registers[i].address, | |
861 | &value, 0); | |
862 | ||
43a431e4 | 863 | data = (u32) value; |
443f18d0 MCC |
864 | |
865 | if (status != DRX_STS_OK) { | |
866 | /* no breakouts; | |
867 | depending on device ID, some HW blocks might not be available */ | |
43a431e4 | 868 | data |= ((u32) status) << 16; |
443f18d0 MCC |
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; | |
38b2df95 DH |
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. | |
43a431e4 | 887 | * \return u16 The data read. |
38b2df95 DH |
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 | */ | |
43a431e4 | 893 | static u16 UCodeRead16(u8 *addr) |
38b2df95 | 894 | { |
443f18d0 | 895 | /* Works fo any host processor */ |
38b2df95 | 896 | |
43a431e4 | 897 | u16 word = 0; |
38b2df95 | 898 | |
43a431e4 | 899 | word = ((u16) addr[0]); |
443f18d0 | 900 | word <<= 8; |
43a431e4 | 901 | word |= ((u16) addr[1]); |
38b2df95 | 902 | |
443f18d0 | 903 | return word; |
38b2df95 DH |
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. | |
43a431e4 | 911 | * \return u32 The data read. |
38b2df95 DH |
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 | */ | |
43a431e4 | 917 | static u32 UCodeRead32(u8 *addr) |
38b2df95 | 918 | { |
443f18d0 | 919 | /* Works fo any host processor */ |
38b2df95 | 920 | |
43a431e4 | 921 | u32 word = 0; |
38b2df95 | 922 | |
43a431e4 | 923 | word = ((u16) addr[0]); |
443f18d0 | 924 | word <<= 8; |
43a431e4 | 925 | word |= ((u16) addr[1]); |
443f18d0 | 926 | word <<= 8; |
43a431e4 | 927 | word |= ((u16) addr[2]); |
443f18d0 | 928 | word <<= 8; |
43a431e4 | 929 | word |= ((u16) addr[3]); |
38b2df95 | 930 | |
443f18d0 | 931 | return word; |
38b2df95 DH |
932 | } |
933 | ||
934 | /*============================================================================*/ | |
935 | ||
936 | /** | |
937 | * \brief Compute CRC of block of microcode data. | |
938 | * \param blockData: Pointer to microcode data. | |
939 | * \param nrWords: Size of microcode block (number of 16 bits words). | |
43a431e4 | 940 | * \return u16 The computed CRC residu. |
38b2df95 | 941 | */ |
43a431e4 | 942 | static u16 UCodeComputeCRC(u8 *blockData, u16 nrWords) |
38b2df95 | 943 | { |
43a431e4 MCC |
944 | u16 i = 0; |
945 | u16 j = 0; | |
946 | u32 CRCWord = 0; | |
947 | u32 carry = 0; | |
443f18d0 MCC |
948 | |
949 | while (i < nrWords) { | |
43a431e4 | 950 | CRCWord |= (u32) UCodeRead16(blockData); |
443f18d0 MCC |
951 | for (j = 0; j < 16; j++) { |
952 | CRCWord <<= 1; | |
953 | if (carry != 0) { | |
954 | CRCWord ^= 0x80050000UL; | |
955 | } | |
956 | carry = CRCWord & 0x80000000UL; | |
957 | } | |
958 | i++; | |
43a431e4 | 959 | blockData += (sizeof(u16)); |
443f18d0 | 960 | } |
43a431e4 | 961 | return ((u16) (CRCWord >> 16)); |
38b2df95 DH |
962 | } |
963 | ||
964 | /*============================================================================*/ | |
965 | ||
966 | /** | |
967 | * \brief Handle microcode upload or verify. | |
968 | * \param devAddr: Address of device. | |
969 | * \param mcInfo: Pointer to information about microcode data. | |
970 | * \param action: Either UCODE_UPLOAD or UCODE_VERIFY | |
971 | * \return DRXStatus_t. | |
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 DRXStatus_t | |
443f18d0 MCC |
985 | CtrlUCode(pDRXDemodInstance_t demod, |
986 | pDRXUCodeInfo_t mcInfo, DRXUCodeAction_t action) | |
38b2df95 | 987 | { |
443f18d0 | 988 | DRXStatus_t rc; |
43a431e4 MCC |
989 | u16 i = 0; |
990 | u16 mcNrOfBlks = 0; | |
991 | u16 mcMagicWord = 0; | |
992 | u8 *mcData = (u8 *) (NULL); | |
5b223b39 | 993 | struct i2c_device_addr *devAddr = (struct i2c_device_addr *) (NULL); |
443f18d0 MCC |
994 | |
995 | devAddr = demod->myI2CDevAddr; | |
996 | ||
997 | /* Check arguments */ | |
998 | if ((mcInfo == NULL) || (mcInfo->mcData == NULL)) { | |
999 | return DRX_STS_INVALID_ARG; | |
1000 | } | |
1001 | ||
1002 | mcData = mcInfo->mcData; | |
1003 | ||
1004 | /* Check data */ | |
1005 | mcMagicWord = UCodeRead16(mcData); | |
43a431e4 | 1006 | mcData += sizeof(u16); |
443f18d0 | 1007 | mcNrOfBlks = UCodeRead16(mcData); |
43a431e4 | 1008 | mcData += sizeof(u16); |
443f18d0 MCC |
1009 | |
1010 | if ((mcMagicWord != DRX_UCODE_MAGIC_WORD) || (mcNrOfBlks == 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 < mcNrOfBlks; i++) { | |
1023 | DRXUCodeBlockHdr_t blockHdr; | |
1024 | ||
1025 | /* Process block header */ | |
1026 | blockHdr.addr = UCodeRead32(mcData); | |
43a431e4 | 1027 | mcData += sizeof(u32); |
443f18d0 | 1028 | blockHdr.size = UCodeRead16(mcData); |
43a431e4 | 1029 | mcData += sizeof(u16); |
443f18d0 | 1030 | blockHdr.flags = UCodeRead16(mcData); |
43a431e4 | 1031 | mcData += sizeof(u16); |
443f18d0 | 1032 | blockHdr.CRC = UCodeRead16(mcData); |
43a431e4 | 1033 | mcData += sizeof(u16); |
443f18d0 MCC |
1034 | |
1035 | if (blockHdr.flags & 0x8) { | |
1036 | /* Aux block. Check type */ | |
43a431e4 MCC |
1037 | u8 *auxblk = mcInfo->mcData + blockHdr.addr; |
1038 | u16 auxtype = UCodeRead16(auxblk); | |
443f18d0 MCC |
1039 | if (DRX_ISMCVERTYPE(auxtype)) { |
1040 | DRX_SET_MCVERTYPE(demod, | |
1041 | UCodeRead16(auxblk)); | |
43a431e4 | 1042 | auxblk += sizeof(u16); |
443f18d0 MCC |
1043 | DRX_SET_MCDEV(demod, |
1044 | UCodeRead32(auxblk)); | |
43a431e4 | 1045 | auxblk += sizeof(u32); |
443f18d0 MCC |
1046 | DRX_SET_MCVERSION(demod, |
1047 | UCodeRead32(auxblk)); | |
43a431e4 | 1048 | auxblk += sizeof(u32); |
443f18d0 MCC |
1049 | DRX_SET_MCPATCH(demod, |
1050 | UCodeRead32(auxblk)); | |
1051 | } | |
1052 | } | |
1053 | ||
1054 | /* Next block */ | |
43a431e4 | 1055 | mcData += blockHdr.size * sizeof(u16); |
443f18d0 MCC |
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 */ | |
43a431e4 | 1067 | mcData = mcInfo->mcData + 2 * sizeof(u16); |
443f18d0 MCC |
1068 | } |
1069 | ||
1070 | /* Process microcode blocks */ | |
1071 | for (i = 0; i < mcNrOfBlks; i++) { | |
1072 | DRXUCodeBlockHdr_t blockHdr; | |
43a431e4 | 1073 | u16 mcBlockNrBytes = 0; |
443f18d0 MCC |
1074 | |
1075 | /* Process block header */ | |
1076 | blockHdr.addr = UCodeRead32(mcData); | |
43a431e4 | 1077 | mcData += sizeof(u32); |
443f18d0 | 1078 | blockHdr.size = UCodeRead16(mcData); |
43a431e4 | 1079 | mcData += sizeof(u16); |
443f18d0 | 1080 | blockHdr.flags = UCodeRead16(mcData); |
43a431e4 | 1081 | mcData += sizeof(u16); |
443f18d0 | 1082 | blockHdr.CRC = UCodeRead16(mcData); |
43a431e4 | 1083 | mcData += sizeof(u16); |
443f18d0 MCC |
1084 | |
1085 | /* Check block header on: | |
1086 | - data larger than 64Kb | |
1087 | - if CRC enabled check CRC | |
1088 | */ | |
1089 | if ((blockHdr.size > 0x7FFF) || | |
1090 | (((blockHdr.flags & DRX_UCODE_CRC_FLAG) != 0) && | |
1091 | (blockHdr.CRC != UCodeComputeCRC(mcData, blockHdr.size))) | |
1092 | ) { | |
1093 | /* Wrong data ! */ | |
1094 | return DRX_STS_INVALID_ARG; | |
1095 | } | |
1096 | ||
43a431e4 | 1097 | mcBlockNrBytes = blockHdr.size * ((u16) sizeof(u16)); |
443f18d0 MCC |
1098 | |
1099 | if (blockHdr.size != 0) { | |
1100 | /* Perform the desired action */ | |
1101 | switch (action) { | |
38b2df95 | 1102 | /*================================================================*/ |
443f18d0 MCC |
1103 | case UCODE_UPLOAD: |
1104 | { | |
1105 | /* Upload microcode */ | |
1106 | if (demod->myAccessFunct-> | |
1107 | writeBlockFunc(devAddr, | |
1108 | (DRXaddr_t) blockHdr. | |
1109 | addr, mcBlockNrBytes, | |
1110 | mcData, | |
1111 | 0x0000) != | |
1112 | DRX_STS_OK) { | |
1113 | return (DRX_STS_ERROR); | |
1114 | } /* if */ | |
1115 | }; | |
1116 | break; | |
38b2df95 DH |
1117 | |
1118 | /*================================================================*/ | |
443f18d0 MCC |
1119 | case UCODE_VERIFY: |
1120 | { | |
1121 | int result = 0; | |
43a431e4 | 1122 | u8 mcDataBuffer |
443f18d0 | 1123 | [DRX_UCODE_MAX_BUF_SIZE]; |
43a431e4 MCC |
1124 | u32 bytesToCompare = 0; |
1125 | u32 bytesLeftToCompare = 0; | |
443f18d0 | 1126 | DRXaddr_t currAddr = (DRXaddr_t) 0; |
43a431e4 | 1127 | u8 *currPtr = NULL; |
443f18d0 MCC |
1128 | |
1129 | bytesLeftToCompare = mcBlockNrBytes; | |
1130 | currAddr = blockHdr.addr; | |
1131 | currPtr = mcData; | |
1132 | ||
1133 | while (bytesLeftToCompare != 0) { | |
1134 | if (bytesLeftToCompare > | |
43a431e4 | 1135 | ((u32) |
443f18d0 MCC |
1136 | DRX_UCODE_MAX_BUF_SIZE)) { |
1137 | bytesToCompare = | |
43a431e4 | 1138 | ((u32) |
443f18d0 MCC |
1139 | DRX_UCODE_MAX_BUF_SIZE); |
1140 | } else { | |
1141 | bytesToCompare = | |
1142 | bytesLeftToCompare; | |
1143 | } | |
1144 | ||
1145 | if (demod->myAccessFunct-> | |
1146 | readBlockFunc(devAddr, | |
1147 | currAddr, | |
43a431e4 | 1148 | (u16) |
443f18d0 | 1149 | bytesToCompare, |
43a431e4 | 1150 | (u8 *) |
443f18d0 MCC |
1151 | mcDataBuffer, |
1152 | 0x0000) != | |
1153 | DRX_STS_OK) { | |
1154 | return (DRX_STS_ERROR); | |
1155 | } | |
1156 | ||
1157 | result = | |
1158 | DRXBSP_HST_Memcmp(currPtr, | |
1159 | mcDataBuffer, | |
1160 | bytesToCompare); | |
1161 | ||
1162 | if (result != 0) { | |
1163 | return DRX_STS_ERROR; | |
1164 | } | |
1165 | ||
1166 | currAddr += | |
1167 | ((DRXaddr_t) | |
1168 | (bytesToCompare / 2)); | |
1169 | currPtr = | |
1170 | &(currPtr[bytesToCompare]); | |
1171 | bytesLeftToCompare -= | |
43a431e4 | 1172 | ((u32) bytesToCompare); |
443f18d0 MCC |
1173 | } /* while( bytesToCompare > DRX_UCODE_MAX_BUF_SIZE ) */ |
1174 | }; | |
1175 | break; | |
38b2df95 DH |
1176 | |
1177 | /*================================================================*/ | |
443f18d0 MCC |
1178 | default: |
1179 | return DRX_STS_INVALID_ARG; | |
1180 | break; | |
38b2df95 | 1181 | |
443f18d0 MCC |
1182 | } /* switch ( action ) */ |
1183 | } | |
38b2df95 | 1184 | |
443f18d0 MCC |
1185 | /* if (blockHdr.size != 0 ) */ |
1186 | /* Next block */ | |
1187 | mcData += mcBlockNrBytes; | |
38b2df95 | 1188 | |
443f18d0 | 1189 | } /* for( i = 0 ; i<mcNrOfBlks ; i++ ) */ |
38b2df95 | 1190 | |
443f18d0 | 1191 | return DRX_STS_OK; |
38b2df95 DH |
1192 | } |
1193 | ||
1194 | /*============================================================================*/ | |
1195 | ||
1196 | /** | |
1197 | * \brief Build list of version information. | |
1198 | * \param demod: A pointer to a demodulator instance. | |
1199 | * \param versionList: Pointer to linked list of versions. | |
1200 | * \return DRXStatus_t. | |
1201 | * \retval DRX_STS_OK: Version information stored in versionList | |
1202 | * \retval DRX_STS_INVALID_ARG: Invalid arguments. | |
1203 | */ | |
1204 | static DRXStatus_t | |
443f18d0 | 1205 | CtrlVersion(pDRXDemodInstance_t demod, pDRXVersionList_t * versionList) |
38b2df95 | 1206 | { |
443f18d0 MCC |
1207 | static char drxDriverCoreModuleName[] = "Core driver"; |
1208 | static char drxDriverCoreVersionText[] = | |
1209 | DRX_VERSIONSTRING(VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH); | |
1210 | ||
1211 | static DRXVersion_t drxDriverCoreVersion; | |
1212 | static DRXVersionList_t drxDriverCoreVersionList; | |
1213 | ||
1214 | pDRXVersionList_t demodVersionList = (pDRXVersionList_t) (NULL); | |
1215 | DRXStatus_t returnStatus = DRX_STS_ERROR; | |
1216 | ||
1217 | /* Check arguments */ | |
1218 | if (versionList == NULL) { | |
1219 | return DRX_STS_INVALID_ARG; | |
1220 | } | |
1221 | ||
1222 | /* Get version info list from demod */ | |
1223 | returnStatus = (*(demod->myDemodFunct->ctrlFunc)) (demod, | |
1224 | DRX_CTRL_VERSION, | |
1225 | (void *) | |
1226 | &demodVersionList); | |
1227 | ||
1228 | /* Always fill in the information of the driver SW . */ | |
1229 | drxDriverCoreVersion.moduleType = DRX_MODULE_DRIVERCORE; | |
1230 | drxDriverCoreVersion.moduleName = drxDriverCoreModuleName; | |
1231 | drxDriverCoreVersion.vMajor = VERSION_MAJOR; | |
1232 | drxDriverCoreVersion.vMinor = VERSION_MINOR; | |
1233 | drxDriverCoreVersion.vPatch = VERSION_PATCH; | |
1234 | drxDriverCoreVersion.vString = drxDriverCoreVersionText; | |
1235 | ||
1236 | drxDriverCoreVersionList.version = &drxDriverCoreVersion; | |
1237 | drxDriverCoreVersionList.next = (pDRXVersionList_t) (NULL); | |
1238 | ||
1239 | if ((returnStatus == DRX_STS_OK) && (demodVersionList != 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 | pDRXVersionList_t currentListElement = demodVersionList; | |
1244 | while (currentListElement->next != NULL) { | |
1245 | currentListElement = currentListElement->next; | |
1246 | } | |
1247 | currentListElement->next = &drxDriverCoreVersionList; | |
1248 | ||
1249 | *versionList = demodVersionList; | |
1250 | } else { | |
1251 | /* Just return versioninfo from driver */ | |
1252 | *versionList = &drxDriverCoreVersionList; | |
1253 | } | |
1254 | ||
1255 | return DRX_STS_OK; | |
38b2df95 DH |
1256 | } |
1257 | ||
1258 | /*============================================================================*/ | |
1259 | /*============================================================================*/ | |
1260 | /*== Exported functions ======================================================*/ | |
1261 | /*============================================================================*/ | |
1262 | /*============================================================================*/ | |
1263 | ||
38b2df95 DH |
1264 | /** |
1265 | * \brief This function is obsolete. | |
1266 | * \param demods: Don't care, parameter is ignored. | |
1267 | * \return DRXStatus_t Return status. | |
1268 | * \retval DRX_STS_OK: Initialization completed. | |
1269 | * | |
1270 | * This function is obsolete, prototype available for backward compatability. | |
1271 | * | |
1272 | */ | |
1273 | ||
443f18d0 | 1274 | DRXStatus_t DRX_Init(pDRXDemodInstance_t demods[]) |
38b2df95 | 1275 | { |
443f18d0 | 1276 | return DRX_STS_OK; |
38b2df95 DH |
1277 | } |
1278 | ||
1279 | /*============================================================================*/ | |
1280 | ||
1281 | /** | |
1282 | * \brief This function is obsolete. | |
1283 | * \return DRXStatus_t Return status. | |
1284 | * \retval DRX_STS_OK: Terminated driver successful. | |
1285 | * | |
1286 | * This function is obsolete, prototype available for backward compatability. | |
1287 | * | |
1288 | */ | |
1289 | ||
443f18d0 | 1290 | DRXStatus_t DRX_Term(void) |
38b2df95 | 1291 | { |
443f18d0 | 1292 | return DRX_STS_OK; |
38b2df95 DH |
1293 | } |
1294 | ||
1295 | /*============================================================================*/ | |
1296 | ||
1297 | /** | |
1298 | * \brief Open a demodulator instance. | |
1299 | * \param demod: A pointer to a demodulator instance. | |
1300 | * \return DRXStatus_t 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 | ||
443f18d0 | 1308 | DRXStatus_t DRX_Open(pDRXDemodInstance_t demod) |
38b2df95 | 1309 | { |
443f18d0 MCC |
1310 | DRXStatus_t status = DRX_STS_OK; |
1311 | ||
1312 | if ((demod == NULL) || | |
1313 | (demod->myDemodFunct == NULL) || | |
1314 | (demod->myCommonAttr == NULL) || | |
1315 | (demod->myExtAttr == NULL) || | |
1316 | (demod->myI2CDevAddr == NULL) || | |
73f7065b | 1317 | (demod->myCommonAttr->isOpened == true)) { |
443f18d0 MCC |
1318 | return (DRX_STS_INVALID_ARG); |
1319 | } | |
1320 | ||
1321 | status = (*(demod->myDemodFunct->openFunc)) (demod); | |
1322 | ||
1323 | if (status == DRX_STS_OK) { | |
73f7065b | 1324 | demod->myCommonAttr->isOpened = true; |
443f18d0 MCC |
1325 | } |
1326 | ||
1327 | return status; | |
38b2df95 DH |
1328 | } |
1329 | ||
1330 | /*============================================================================*/ | |
1331 | ||
1332 | /** | |
1333 | * \brief Close device. | |
1334 | * \param demod: A pointer to a demodulator instance. | |
1335 | * \return DRXStatus_t 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 | ||
443f18d0 | 1345 | DRXStatus_t DRX_Close(pDRXDemodInstance_t demod) |
38b2df95 | 1346 | { |
443f18d0 | 1347 | DRXStatus_t status = DRX_STS_OK; |
38b2df95 | 1348 | |
443f18d0 MCC |
1349 | if ((demod == NULL) || |
1350 | (demod->myDemodFunct == NULL) || | |
1351 | (demod->myCommonAttr == NULL) || | |
1352 | (demod->myExtAttr == NULL) || | |
1353 | (demod->myI2CDevAddr == NULL) || | |
73f7065b | 1354 | (demod->myCommonAttr->isOpened == false)) { |
443f18d0 MCC |
1355 | return DRX_STS_INVALID_ARG; |
1356 | } | |
38b2df95 | 1357 | |
443f18d0 | 1358 | status = (*(demod->myDemodFunct->closeFunc)) (demod); |
38b2df95 | 1359 | |
73f7065b | 1360 | DRX_SET_ISOPENED(demod, false); |
38b2df95 | 1361 | |
443f18d0 | 1362 | return status; |
38b2df95 DH |
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 ctrlData: Pointer to data structure for control function. | |
1372 | * \return DRXStatus_t 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 ctrlData 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 ctrlData. | |
1382 | * | |
1383 | */ | |
1384 | ||
1385 | DRXStatus_t | |
1386 | DRX_Ctrl(pDRXDemodInstance_t demod, DRXCtrlIndex_t ctrl, void *ctrlData) | |
1387 | { | |
443f18d0 MCC |
1388 | DRXStatus_t status = DRX_STS_ERROR; |
1389 | ||
1390 | if ((demod == NULL) || | |
1391 | (demod->myDemodFunct == NULL) || | |
1392 | (demod->myCommonAttr == NULL) || | |
1393 | (demod->myExtAttr == NULL) || (demod->myI2CDevAddr == NULL) | |
1394 | ) { | |
1395 | return (DRX_STS_INVALID_ARG); | |
1396 | } | |
1397 | ||
73f7065b | 1398 | if (((demod->myCommonAttr->isOpened == false) && |
443f18d0 MCC |
1399 | (ctrl != DRX_CTRL_PROBE_DEVICE) && (ctrl != DRX_CTRL_VERSION)) |
1400 | ) { | |
1401 | return (DRX_STS_INVALID_ARG); | |
1402 | } | |
1403 | ||
1404 | if ((DRX_ISPOWERDOWNMODE(demod->myCommonAttr->currentPowerMode) && | |
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) { | |
38b2df95 | 1415 | /*======================================================================*/ |
443f18d0 MCC |
1416 | case DRX_CTRL_NOP: |
1417 | /* No operation */ | |
1418 | return DRX_STS_OK; | |
1419 | break; | |
38b2df95 DH |
1420 | |
1421 | /*======================================================================*/ | |
443f18d0 MCC |
1422 | case DRX_CTRL_VERSION: |
1423 | return CtrlVersion(demod, (pDRXVersionList_t *) ctrlData); | |
1424 | break; | |
38b2df95 DH |
1425 | |
1426 | /*======================================================================*/ | |
443f18d0 MCC |
1427 | default: |
1428 | /* Do nothing */ | |
1429 | break; | |
1430 | } | |
1431 | ||
1432 | /* Virtual functions */ | |
1433 | /* First try calling function from derived class */ | |
1434 | status = (*(demod->myDemodFunct->ctrlFunc)) (demod, ctrl, ctrlData); | |
1435 | if (status == DRX_STS_FUNC_NOT_AVAILABLE) { | |
1436 | /* Now try calling a the base class function */ | |
1437 | switch (ctrl) { | |
38b2df95 | 1438 | /*===================================================================*/ |
443f18d0 MCC |
1439 | case DRX_CTRL_LOAD_UCODE: |
1440 | return CtrlUCode(demod, | |
1441 | (pDRXUCodeInfo_t) ctrlData, | |
1442 | UCODE_UPLOAD); | |
1443 | break; | |
38b2df95 DH |
1444 | |
1445 | /*===================================================================*/ | |
443f18d0 MCC |
1446 | case DRX_CTRL_VERIFY_UCODE: |
1447 | { | |
1448 | return CtrlUCode(demod, | |
1449 | (pDRXUCodeInfo_t) ctrlData, | |
1450 | UCODE_VERIFY); | |
1451 | } | |
1452 | break; | |
38b2df95 DH |
1453 | |
1454 | #ifndef DRX_EXCLUDE_SCAN | |
1455 | /*===================================================================*/ | |
443f18d0 MCC |
1456 | case DRX_CTRL_SCAN_INIT: |
1457 | { | |
1458 | return CtrlScanInit(demod, | |
1459 | (pDRXScanParam_t) ctrlData); | |
1460 | } | |
1461 | break; | |
38b2df95 DH |
1462 | |
1463 | /*===================================================================*/ | |
443f18d0 MCC |
1464 | case DRX_CTRL_SCAN_NEXT: |
1465 | { | |
43a431e4 | 1466 | return CtrlScanNext(demod, (u16 *) ctrlData); |
443f18d0 MCC |
1467 | } |
1468 | break; | |
38b2df95 DH |
1469 | |
1470 | /*===================================================================*/ | |
443f18d0 MCC |
1471 | case DRX_CTRL_SCAN_STOP: |
1472 | { | |
1473 | return CtrlScanStop(demod); | |
1474 | } | |
1475 | break; | |
38b2df95 DH |
1476 | #endif /* #ifndef DRX_EXCLUDE_SCAN */ |
1477 | ||
1478 | /*===================================================================*/ | |
443f18d0 MCC |
1479 | case DRX_CTRL_PROGRAM_TUNER: |
1480 | { | |
1481 | return CtrlProgramTuner(demod, | |
1482 | (pDRXChannel_t) | |
1483 | ctrlData); | |
1484 | } | |
1485 | break; | |
38b2df95 DH |
1486 | |
1487 | /*===================================================================*/ | |
443f18d0 MCC |
1488 | case DRX_CTRL_DUMP_REGISTERS: |
1489 | { | |
1490 | return CtrlDumpRegisters(demod, | |
1491 | (pDRXRegDump_t) | |
1492 | ctrlData); | |
1493 | } | |
1494 | break; | |
38b2df95 DH |
1495 | |
1496 | /*===================================================================*/ | |
443f18d0 MCC |
1497 | default: |
1498 | return DRX_STS_FUNC_NOT_AVAILABLE; | |
1499 | } | |
1500 | } else { | |
1501 | return (status); | |
1502 | } | |
1503 | ||
1504 | return DRX_STS_OK; | |
38b2df95 DH |
1505 | } |
1506 | ||
38b2df95 DH |
1507 | /*============================================================================*/ |
1508 | ||
1509 | /* END OF FILE */ |