blob: 5a347f902e41f4304596d3bf86552755354dde53 [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001/******************************************************************************
2
3 Copyright (c) 2014-2015 Lantiq Deutschland GmbH
4 Copyright (c) 2015-2016 Lantiq Beteiligungs-GmbH & Co.KG
5 Copyright 2016, Intel Corporation.
6
7 For licensing information, see the file 'LICENSE' in the root folder of
8 this software module.
9
10******************************************************************************/
11
12/**
13 \file dxs_outbox.c
14*/
15
16/* ========================================================================== */
17/* Includes */
18/* ========================================================================== */
19#include <stdio.h>
20#include <errno.h>
21
22#include "dxs_config.h"
23#include "dxs.h"
24#include "dxs_lib.h"
25#include "dxs_mbx.h"
26#include "dxs_errno.h"
27#include "dxs_error.h"
28#include "dxs_event.h"
29#include "dxs_sdd.h"
30#include "dxs_sig.h"
31#include "dxs_cid_fsk.h"
32#include "dxs_cid.h"
33#include "dxs_init.h"
34#include "dxs_dcdc_hw.h"
35#ifdef EVENT_LOGGER_DEBUG
36#include <sys/ioctl.h>
37#endif
38
39/* ========================================================================== */
40/* Macro definitions */
41/* ========================================================================== */
42/*#define DXS_CMD_PRINT*/
43#undef DXS_CMD_PRINT
44//#define DXS_CMD_PRINT
45
46/* SDD events */
47/** Over temperature detected */
48#define EVT_SDD_OTEMP 0
49/** Line testing finished */
50#define EVT_SDD_LT_FIN 1
51/** Ground fault detected */
52#define EVT_SDD_GF 3
53/** Ground key detected */
54#define EVT_SDD_GK 4
55/** Opmode changed */
56#define EVT_SDD_OPC 5
57/** Error in command SDD_CoeffReadConfig */
58#define EVT_SDD_CORCE 6
59/** Error in command SDD_Coeff */
60#define EVT_SDD_COEFE 7
61/** On-hook */
62#define EVT_SDD_ONH 9
63/** Off-hook */
64#define EVT_SDD_OFFH 10
65/** Ground Fault Finished */
66#define EVT_SDD_GF_FIN 12
67/** Ground Key Finished */
68#define EVT_SDD_GK_FIN 13
69/** Overtemp finished which means that
70 SLIC temperature is back in normal range */
71#define EVT_SDD_OTEMP_FIN 14
72/** Operating Mode Ignored */
73#define EVT_SDD_OMI 17
74/** Operating Mode discarded */
75#define EVT_SDD_OPM_DIS 18
76/** Line testing aborted */
77#define EVT_SDD_LT_ABORT 19
78
79/* SIG events */
80/** DTMF detector */
81#define EVT_SIG_DTMF_DET 1
82/** Caller ID sender request */
83#define EVT_SIG_CIS_REQ 2
84/** Caller ID sender buffer underflow */
85#define EVT_SIG_CIS_BUF 3
86/** Caller ID sender has finished sending data */
87#define EVT_SIG_CIS_FIN 4
88/** Start of tone detected */
89#define EVT_SIG_UTD_START 5
90/** End of tone detected */
91#define EVT_SIG_UTD_END 6
92/** Metering pulse sent */
93#define EVT_SIG_TTX_FIN 9
94/** AC level metering finished */
95#define EVT_SIG_AC_LM_FIN 10
96
97/* ========================================================================== */
98/* Type definitions */
99/* ========================================================================== */
100struct __fw_evt_header
101{
102#if __BYTE_ORDER == __BIG_ENDIAN
103 /* Reserved */
104 uint32_t Res00 : 3;
105 /* Command Type */
106 uint32_t CMD : 5;
107 /* Channel */
108 uint32_t CHAN : 8;
109 /* Command Mode */
110 uint32_t MOD : 3;
111 /* Command Sub-Mode */
112 uint32_t ECMD : 5;
113 /* Length of Command Payload */
114 uint32_t LENGTH : 8;
115#else
116 /* Length of Command Payload */
117 uint32_t LENGTH : 8;
118 /* Command Sub-Mode */
119 uint32_t ECMD : 5;
120 /* Command Mode */
121 uint32_t MOD : 3;
122 /* Channel */
123 uint32_t CHAN : 8;
124 /* Command Type */
125 uint32_t CMD : 5;
126 /* Reserved */
127 uint32_t Res00 : 3;
128#endif
129} __attribute__ ((packed));
130
131struct __fw_evt_int_err
132{
133 struct __fw_evt_header hdr;
134#if __BYTE_ORDER == __BIG_ENDIAN
135 /* Reserved */
136 uint32_t Res01 : 27;
137 /* Event Code */
138 uint32_t ERREVT : 5;
139#else
140 /* Event Code */
141 uint32_t ERREVT : 5;
142 /* Reserved */
143 uint32_t Res01 : 27;
144#endif
145} __attribute__ ((packed));
146
147struct __fw_evt_cmd_err
148{
149 struct __fw_evt_header hdr;
150#if __BYTE_ORDER == __BIG_ENDIAN
151 /* Reserved */
152 uint32_t Res01 : 18;
153 /* Error Cause */
154 uint32_t CMDERR : 14;
155 /* Command Header of Command */
156 uint32_t CMDHDR;
157#else
158 /* Error Cause */
159 uint32_t CMDERR : 14;
160 /* Reserved */
161 uint32_t Res01 : 18;
162 /* Command Header of Command */
163 uint32_t CMDHDR;
164#endif
165} __attribute__ ((packed));
166
167struct __fw_evt_sdd
168{
169 struct __fw_evt_header hdr;
170#if __BYTE_ORDER == __BIG_ENDIAN
171 /* Time Stamp */
172 uint32_t TIME_STAMP : 16;
173 /* Analog line operating mode */
174 uint32_t OPMODE : 8;
175 /* Reserved */
176 uint32_t Res01 : 3;
177 /* Event code */
178 uint32_t EVT : 5;
179#else
180 /* Event code */
181 uint32_t EVT : 5;
182 /* Reserved */
183 uint32_t Res01 : 3;
184 /* Analog line operating mode */
185 uint32_t OPMODE : 8;
186 /* Time Stamp */
187 uint32_t TIME_STAMP : 16;
188#endif
189} __attribute__ ((packed));
190
191struct __fw_evt_sig
192{
193 struct __fw_evt_header hdr;
194#if __BYTE_ORDER == __BIG_ENDIAN
195 /* Time Stamp */
196 uint32_t TIME_STAMP : 16;
197 /* Reserved */
198 uint32_t Res01 : 4;
199 /* DTMF Key */
200 uint32_t DTMF_KEY : 4;
201 /* Reserved */
202 uint32_t Res02 : 3;
203 /* Event code */
204 uint32_t SIGEVT : 5;
205#else
206 /* Event code */
207 uint32_t SIGEVT : 5;
208 /* Reserved */
209 uint32_t Res02 : 3;
210 /* DTMF Key */
211 uint32_t DTMF_KEY : 4;
212 /* Reserved */
213 uint32_t Res01 : 4;
214 /* Time Stamp */
215 uint32_t TIME_STAMP : 16;
216#endif
217} __attribute__ ((packed));
218
219/* ========================================================================== */
220/* Global variables */
221/* ========================================================================== */
222
223/* ========================================================================== */
224/* Function prototypes */
225/* ========================================================================== */
226
227/* ========================================================================== */
228/* Function implementation */
229/* ========================================================================== */
230#ifdef EVENT_LOGGER_DEBUG
231static void dxs_el_trace_event_read(DXS_DEVICE_t *pDev,
232 struct __fw_evt_header *pHdr)
233{
234 EL_IoctlAddLog_t stLog;
235 stLog.nLogType = EL_LOG_TYPE_EVT_MBX_RD;
236 stLog.nOrygLogType = EL_MAX_LOG_TYPE;
237 stLog.nDevType = DXS_LIB_DEV_TYPE;
238 stLog.nDevNum = pDev->nDevNum;
239 stLog.nChNum = pHdr->CHAN;
240 stLog.uLogDetails.stEvt_Mbx_Rd.nCmdLength = 4;
241 stLog.uLogDetails.stEvt_Mbx_Rd.nCount = pHdr->LENGTH + 4;
242 stLog.uLogDetails.stEvt_Mbx_Rd.nDataLength = pHdr->LENGTH;
243 stLog.uLogDetails.stEvt_Mbx_Rd.pCmd = (char*)pHdr;
244 if(pHdr->LENGTH == 0)
245 {
246 stLog.uLogDetails.stEvt_Mbx_Rd.pDATA = NULL;
247 }
248 else
249 {
250 stLog.uLogDetails.stEvt_Mbx_Rd.pDATA = (IFX_char_t*)((int16_t*) pHdr + 2);
251 }
252 ioctl(pDev->el_fd, EL_ADD_LOG, (int32_t)&stLog);
253}
254#endif
255
256/**
257 Dispatch raw off-hook event
258
259 \param pCh - pointer to DXS channel structure
260 \return none
261*/
262static void dxs_evt_offhook_raw (DXS_CHANNEL_t *pCh)
263{
264 DXS_Event_t evt = {0};
265
266 evt.dev = pCh->pParent->nDevNum;
267 evt.ch = pCh->nCh;
268 evt.id = DXS_EVENT_FXS_RAW_OFFHOOK;
269 DXS_EventDispatch(pCh->pParent, &evt);
270}
271
272/**
273 Dispatch raw on-hook event
274
275 \param pCh - pointer to DXS channel structure
276 \return none
277*/
278static void dxs_evt_onhook_raw (DXS_CHANNEL_t *pCh)
279{
280 DXS_Event_t evt = {0};
281
282 evt.dev = pCh->pParent->nDevNum;
283 evt.ch = pCh->nCh;
284 evt.id = DXS_EVENT_FXS_RAW_ONHOOK;
285 DXS_EventDispatch(pCh->pParent, &evt);
286}
287
288/**
289 Function dxs_cerr_ack
290
291 \param pDev - pointer to DXS device structure
292
293 \return
294 - DXS_status_t
295*/
296static int32_t dxs_cerr_ack(DXS_DEVICE_t *pDev)
297{
298 uint32_t cerr_ack_cmd = 0x0600e000;
299
300 return DXS_CmdWrite(pDev, &cerr_ack_cmd);
301}
302
303/**
304 Function dxs_event_sdd
305
306 \param pDev - pointer to DXS device structure
307 \param pSddEvt - pointer to SDD event structure
308
309*/
310static void dxs_event_sdd(DXS_DEVICE_t *pDev, struct __fw_evt_sdd *pSddEvt)
311{
312 DXS_Event_t dxs_event = {0};
313 int32_t ret;
314 uint8_t nTmp;
315 DXS_CHANNEL_t *pCh = &pDev->pChannel[pSddEvt->hdr.CHAN];
316
317 dxs_event.dev = pDev->nDevNum;
318 dxs_event.ch = pSddEvt->hdr.CHAN;
319
320 switch (pSddEvt->EVT)
321 {
322 case EVT_SDD_OTEMP:
323 dxs_event.id = DXS_EVENT_OVERTEMP;
324 DXS_EventDispatch(pDev, &dxs_event);
325 break;
326
327 case EVT_SDD_OTEMP_FIN:
328 DXS_SDD_LineModeSet(pCh, DXS_LINE_FEED_DISABLED);
329 dxs_event.id = DXS_EVENT_OVERTEMP_END;
330 DXS_EventDispatch(pDev, &dxs_event);
331 break;
332
333 case EVT_SDD_LT_FIN:
334#if defined(DXS_FEAT_CAPMEAS) && defined(DXS_FEAT_GR909)
335 obx_DXS_SDD_OLCalibrationFinished(pCh, 0);
336#endif /* DXS_FEAT_CAPMEAS && DXS_FEAT_GR909 */
337 dxs_event.id = DXS_EVENT_NLT_END;
338 DXS_EventDispatch(pDev, &dxs_event);
339 break;
340
341 case EVT_SDD_LT_ABORT:
342#if defined(DXS_FEAT_CAPMEAS) && defined(DXS_FEAT_GR909)
343 obx_DXS_SDD_OLCalibrationFinished(pCh, 1);
344#endif /* DXS_FEAT_CAPMEAS && DXS_FEAT_GR909 */
345 dxs_event.id = DXS_EVENT_NLT_ABORT;
346 DXS_EventDispatch(pDev, &dxs_event);
347 break;
348
349 case EVT_SDD_GF:
350 dxs_event.id = DXS_EVENT_GROUND_FAULT;
351 DXS_EventDispatch(pDev, &dxs_event);
352 break;
353
354 case EVT_SDD_GF_FIN:
355 DXS_SDD_LineModeSet(pCh, DXS_LINE_FEED_DISABLED);
356 dxs_event.id = DXS_EVENT_GROUND_FAULT_END;
357 DXS_EventDispatch(pDev, &dxs_event);
358 break;
359
360 case EVT_SDD_GK:
361 dxs_event.id = DXS_EVENT_GROUND_KEY;
362 DXS_EventDispatch(pDev, &dxs_event);
363 break;
364
365 case EVT_SDD_GK_FIN:
366 dxs_event.id = DXS_EVENT_GROUND_KEY_END;
367 DXS_EventDispatch(pDev, &dxs_event);
368 break;
369
370 case EVT_SDD_OPC:
371 case EVT_SDD_OMI:
372 {
373 uint8_t opmode_changed = (pSddEvt->EVT == EVT_SDD_OPC) ? 1 : 0;
374
375 /*DXS_DCDC_HW_Lock(pCh);*/
376 obx_DXS_SDD_OpmodeUpdate(pCh, pSddEvt->OPMODE, opmode_changed);
377 /*DXS_DCDC_HW_UnLock(pCh);*/
378
379 /* For some OPC events more actions are needed */
380 if (opmode_changed)
381 {
382#ifdef DXS_FEAT_HSM
383 /* Set hook-state to ONHOOK if opmode was changed to disabled */
384 if (pSddEvt->OPMODE == DXS_LINE_FEED_DISABLED)
385 {
386#ifdef DXS_FEAT_CID
387 if (DXS_CID_EventOpcDisabled(pCh))
388#endif
389 {
390 DXS_Dial_HookStateSetOnhook(pCh);
391 }
392 }
393#endif
394 /* Calibration ends with an opmode change */
395 if (pSddEvt->OPMODE != DXS_LINE_FEED_CALIBRATE)
396 {
397 ret = DXS_SDD_CalibrationRunningGet(pCh, &nTmp);
398 /* if calibration was running, signal that it has finished */
399 if (ret == DXS_statusOk && nTmp == 1)
400 DXS_SDD_Calibration_Finish(pCh, &dxs_event);
401 }
402 }
403 }
404 break;
405
406 case EVT_SDD_CORCE:
407 break;
408 case EVT_SDD_COEFE:
409 break;
410 case EVT_SDD_ONH:
411 /* Report RAW on-hook */
412 dxs_evt_onhook_raw(pCh);
413#ifdef DXS_FEAT_CID
414 /* Report on-hook */
415 if (DXS_CID_EventOnhook(pCh, pSddEvt->TIME_STAMP))
416#endif
417 {
418#ifdef DXS_FEAT_HSM
419 DXS_Dial_HookEvent(pCh, 0, pSddEvt->TIME_STAMP);
420#else
421 dxs_event.id = DXS_EVENT_FXS_ONHOOK;
422 DXS_EventDispatch(pDev, &dxs_event);
423#endif
424 }
425 break;
426
427 case EVT_SDD_OFFH:
428 /* Report RAW off-hook */
429 dxs_evt_offhook_raw(pCh);
430#ifdef DXS_FEAT_FSK
431 /* Attempt to disable FSK generator */
432 DXS_FSK_Disable(pCh, 0);
433#endif
434#ifdef DXS_FEAT_CID
435 /* Report off-hook */
436 if (DXS_CID_EventOffhook(pCh, pSddEvt->TIME_STAMP))
437#endif
438 {
439#ifdef DXS_FEAT_HSM
440 DXS_Dial_HookEvent(pCh, 1, pSddEvt->TIME_STAMP);
441#else
442 dxs_event.id = DXS_EVENT_FXS_OFFHOOK;
443 DXS_EventDispatch(pDev, &dxs_event);
444#endif
445 }
446 break;
447
448 case EVT_SDD_OPM_DIS:
449 break;
450
451 default:
452 break;
453 }
454}
455
456/**
457 Function dxs_event_sig
458
459 \param pDev - pointer to DXS device structure
460 \param pSigEvt - pointer to SIG event structure
461
462*/
463static void dxs_event_sig(DXS_DEVICE_t *pDev, struct __fw_evt_sig *pSigEvt)
464{
465 DXS_Event_t dxs_event = {0};
466#if defined (DXS_FEAT_CID) || defined (DXS_FEAT_UTD) || defined (DXS_FEAT_METERING) || defined (DXS_FEAT_ACMETER)
467 DXS_CHANNEL_t *pCh = &pDev->pChannel[pSigEvt->hdr.CHAN];
468#endif
469 dxs_event.dev = pDev->nDevNum;
470 dxs_event.ch = pSigEvt->hdr.CHAN;
471
472 switch (pSigEvt->SIGEVT)
473 {
474 case EVT_SIG_DTMF_DET:
475 {
476 dxs_event.id = DXS_EVENT_DTMF_DIGIT;
477 switch (pSigEvt->DTMF_KEY)
478 {
479 case 0x0:
480 dxs_event.data.dtmf.digit = 11;
481 dxs_event.data.dtmf.ascii = '0';
482 break;
483 case 0x1:
484 case 0x2:
485 case 0x3:
486 case 0x4:
487 case 0x5:
488 case 0x6:
489 case 0x7:
490 case 0x8:
491 case 0x9:
492 dxs_event.data.dtmf.digit = pSigEvt->DTMF_KEY;
493 dxs_event.data.dtmf.ascii = '0' + pSigEvt->DTMF_KEY;
494 break;
495 case 0xA:
496 dxs_event.data.dtmf.digit = 10;
497 dxs_event.data.dtmf.ascii = '*';
498 break;
499 case 0xB:
500 dxs_event.data.dtmf.digit = 12;
501 dxs_event.data.dtmf.ascii = '#';
502 break;
503 case 0xC:
504 dxs_event.data.dtmf.digit = 28;
505 dxs_event.data.dtmf.ascii = 'A';
506 break;
507 case 0xD:
508 dxs_event.data.dtmf.digit = 29;
509 dxs_event.data.dtmf.ascii = 'B';
510 break;
511 case 0xE:
512 dxs_event.data.dtmf.digit = 30;
513 dxs_event.data.dtmf.ascii = 'C';
514 break;
515 case 0xF:
516 dxs_event.data.dtmf.digit = 31;
517 dxs_event.data.dtmf.ascii = 'D';
518 break;
519 default:
520 break;
521 }
522#ifdef DXS_FEAT_CID
523 /* Report dtmf tone */
524 if (DXS_CID_EventDtmf(pCh, &dxs_event))
525#endif
526 {
527 DXS_EventDispatch(pDev, &dxs_event);
528 break;
529 }
530 }
531 break;
532
533#if defined(DXS_FEAT_FSK) || defined(DXS_FEAT_CID)
534 case EVT_SIG_CIS_REQ:
535 dxs_event.id = DXS_EVENT_CID_REQ_DATA;
536 DXS_EventDispatch(pDev, &dxs_event);
537#ifdef DXS_FEAT_CID
538 /* inform FSK state machine */
539 DXS_CID_FSK_EventInfo (pCh, DXS_CID_FSK_DATA_REQUEST);
540#endif /* DXS_FEAT_CID */
541 break;
542 case EVT_SIG_CIS_BUF:
543 dxs_event.id = DXS_EVENT_CID_BUF_UNDERFLOW;
544 DXS_EventDispatch(pDev, &dxs_event);
545#ifdef DXS_FEAT_CID
546 /* inform FSK state machine */
547 DXS_CID_FSK_EventInfo (pCh, DXS_CID_FSK_DATA_BUF);
548#endif /* DXS_FEAT_CID */
549 break;
550 case EVT_SIG_CIS_FIN:
551 dxs_event.id = DXS_EVENT_CID_END;
552 DXS_EventDispatch(pDev, &dxs_event);
553#ifdef DXS_FEAT_CID
554 /* inform FSK state machine */
555 DXS_CID_FSK_EventInfo (pCh, DXS_CID_FSK_DATA_FINISH);
556#endif /* DXS_FEAT_CID */
557 break;
558#endif /* DXS_FEAT_FSK || DXS_FEAT_CID */
559
560#ifdef DXS_FEAT_UTD
561 case EVT_SIG_UTD_START:
562 dxs_event.id = DXS_EVENT_TONE_DET_CPT;
563 dxs_event.data.tone_det.index = DXS_UTD_ToneIdxGet(pCh);
564 DXS_EventDispatch(pDev, &dxs_event);
565 break;
566 case EVT_SIG_UTD_END:
567 dxs_event.id = DXS_EVENT_TONE_DET_CPT_END;
568 dxs_event.data.tone_det.index = DXS_UTD_ToneIdxGet(pCh);
569 DXS_EventDispatch(pDev, &dxs_event);
570 break;
571#endif /* DXS_FEAT_UTD */
572
573#ifdef DXS_FEAT_METERING
574 case EVT_SIG_TTX_FIN:
575 obx_DXS_SIG_MeterPulseStatusClear(pCh);
576 dxs_event.id = DXS_EVENT_METERING_END;
577 DXS_EventDispatch(pDev, &dxs_event);
578 break;
579#endif /* DXS_FEAT_METERING */
580
581#ifdef DXS_FEAT_ACMETER
582 case EVT_SIG_AC_LM_FIN:
583 obx_DXS_SDD_ACLM_Finish(pCh);
584 break;
585#endif /* DXS_FEAT_ACMETER */
586
587 default:
588 break;
589 }
590}
591
592/**
593 Function dxs_handle_event
594
595 \param pDev Pointer to DXS device structure.
596 \param pHdr Pointer to __fw_evt_header structure.
597*/
598static void dxs_handle_event(DXS_DEVICE_t *pDev, struct __fw_evt_header *pHdr)
599{
600 /* Discard all events here while event handling is globally disabled. */
601 if (pDev->obxDiscardEvents != 0)
602 {
603#ifdef DXS_CMD_PRINT
604 /* The boot finished event has only one word all other two words. */
605 if (pHdr->MOD == 7 && pHdr->ECMD == 0)
606 fprintf (stderr, "[evt] dev:%d %08X DISCARDED\n",
607 pDev->nDevNum, *((uint32_t *)pHdr));
608 else
609 fprintf (stderr, "[evt] dev:%d %08X %08X DISCARDED\n", pDev->nDevNum,
610 *((uint32_t *)pHdr), *((uint32_t *)pHdr + 1));
611#endif /* DXS_CMD_PRINT */
612 return;
613 }
614
615 if (pHdr->MOD == 7 && pHdr->ECMD == 0)
616 {
617 /* Boot Finished Event */
618
619 uint8_t i;
620
621#ifdef DXS_CMD_PRINT
622 fprintf (stderr, "[evt] dev:%d %08X\n", pDev->nDevNum,
623 *((uint32_t *)pHdr));
624#endif /* DXS_CMD_PRINT */
625
626 /* clear flags and capabilities */
627 dxs_caps_vers_forget(pDev);
628 pDev->flags &= ~DXS_DEV_PRAM_PATCH_DOWNLOADED;
629 for (i=0; i<CH_PER_DEVICE; i++)
630 {
631 DXS_CHANNEL_t *pCh = &pDev->pChannel[i];
632
633 pCh->flags &= ~DXS_CH_BBD_DOWNLOADED;
634 }
635
636 if (pDev->bWaitingInPatchDwld)
637 {
638 sem_post(&pDev->mtxPatchDwld);
639 pDev->bWaitingInPatchDwld = 0;
640 }
641 else
642 {
643 /* FW crash */
644
645 DXS_Event_t dxs_event = {0};
646
647 dxs_event.dev = pDev->nDevNum;
648 dxs_event.ch = 0;
649 dxs_event.id = DXS_EVENT_FAULT_FW_WATCHDOG;
650 DXS_EventDispatch(pDev, &dxs_event);
651 }
652 }
653
654 if (pHdr->MOD == 7 && pHdr->ECMD == 11)
655 {
656 /* Internal Error Event */
657
658#ifdef DXS_CMD_PRINT
659 fprintf (stderr, "[evt] dev:%d %08X %08X\n", pDev->nDevNum,
660 *((uint32_t *)pHdr), *((uint32_t *)pHdr + 1));
661#endif /* DXS_CMD_PRINT */
662 }
663 else if (pHdr->MOD == 7 && pHdr->ECMD == 2)
664 {
665 /* Command Error Event */
666
667 struct __fw_evt_cmd_err *pCerr = (struct __fw_evt_cmd_err *)pHdr;
668 DXS_Event_t dxs_event = {0};
669
670#ifdef DXS_CMD_PRINT
671 fprintf (stderr, "[evt] dev:%d %08X %08X %08X\n", pDev->nDevNum,
672 *((uint32_t *)pHdr), *((uint32_t *)pHdr + 1),
673 *((uint32_t *)pHdr + 2));
674#endif /* DXS_CMD_PRINT */
675
676 /* acknowledge command error */
677 dxs_cerr_ack(pDev);
678
679 dxs_event.dev = pDev->nDevNum;
680 dxs_event.id = DXS_EVENT_DEBUG_CERR;
681 dxs_event.data.cerr.reason = pCerr->CMDERR;
682 dxs_event.data.cerr.command = pCerr->CMDHDR;
683 DXS_EventDispatch(pDev, &dxs_event);
684 }
685 else if (pHdr->MOD == 1 && pHdr->ECMD == 4)
686 {
687 /* SDD Event */
688
689#ifdef DXS_CMD_PRINT
690 fprintf (stderr, "[evt] dev:%d %08X %08X\n", pDev->nDevNum,
691 *((uint32_t *)pHdr), *((uint32_t *)pHdr + 1));
692#endif /* DXS_CMD_PRINT */
693
694 dxs_event_sdd(pDev, (struct __fw_evt_sdd *)pHdr);
695 }
696 else if (pHdr->MOD == 1 && pHdr->ECMD == 5)
697 {
698 /* Signaling Event */
699
700#ifdef DXS_CMD_PRINT
701 fprintf (stderr, "[evt] dev:%d %08X %08X\n", pDev->nDevNum,
702 *((uint32_t *)pHdr), *((uint32_t *)pHdr + 1));
703#endif /* DXS_CMD_PRINT */
704
705 dxs_event_sig(pDev, (struct __fw_evt_sig *)pHdr);
706 }
707}
708
709/**
710 Function dxs_outbox_handler
711
712 \param arg - pointer to device
713
714*/
715static void *dxs_outbox_handler (void *arg)
716{
717 DXS_DEVICE_t *pDev = (DXS_DEVICE_t *)arg;
718
719 while (pDev->obxThreadStop == 0)
720 {
721 uint8_t words16, words32, msg_len/*in 32-bit words*/, tmp,
722 words32_remaining;
723 /* 16 bit index points to the header of message that has been read out */
724 uint8_t pos1;
725 int32_t ret;
726
727 ret = sem_wait (&pDev->obxSemaphore);
728 if (ret == EINTR)
729 pthread_exit((void *)DXS_statusOk);
730
731 /* TODO:- take additional mutex (trylock ???) - concurrency with CmdRead() */
732 /* TODO: check if SPI works */
733
734 /* read the outbox */
735 DXS_ObxRead(pDev, pDev->dmbx, &words16);
736
737 if (words16 == 0)
738 {
739 continue;
740 }
741 if (words16 & 1)
742 {
743 /* TODO: is this an error ? */
744 fprintf (stderr, "OutMbx: Odd word count: %d\n", words16);
745 continue;
746 }
747
748 words32_remaining = words32 = words16 >> 1;
749 pos1 = 0;
750
751 while ((pos1/2) < words32)
752 {
753 struct __fw_evt_header *pHdr = (struct __fw_evt_header *)(pDev->dmbx+pos1);
754 uint8_t attempts = 0, out_of_sync = 0;
755
756 /* get the length of the message in 32-bit words */
757 msg_len = (pHdr->LENGTH + sizeof(struct __fw_evt_header)) >> 2;
758
759 while (msg_len > words32_remaining)
760 {
761 /* read 2nd segment */
762
763 /* read the outbox again */
764 DXS_ObxRead(pDev, pDev->dmbx + words16, &tmp);
765
766 /* here we don't expect that nothing is read */
767
768 words16 += tmp;
769 words32 = words16 >> 1;
770 words32_remaining += (tmp >> 1);
771
772 if (++attempts == 3)
773 {
774 out_of_sync = 1;
775 break;
776 }
777 }
778
779 if (out_of_sync)
780 {
781 int32_t i;
782 fprintf (stderr, "Mailbox out of sync.\n");
783 /* print the read buffer */
784 fprintf (stderr, "READ BUFFER:\n");
785 for (i=0; i<(sizeof(pDev->dmbx)>>1); i+=2)
786 fprintf (stderr, "%02d: %04X %04X\n", i, pDev->dmbx[i], pDev->dmbx[i+1]);
787 fprintf (stderr, "pos=%02d\n", pos1);
788 break;
789 }
790
791 /* decode message, buffer it, advance to the next */
792 if (pHdr->Res00 == 0 &&
793 pHdr->CMD == 9 &&
794 (pHdr->MOD == 1 || pHdr->MOD == 7) &&
795 (pHdr->LENGTH == 0 || pHdr->LENGTH == 4 || pHdr->LENGTH == 8))
796 {
797#ifdef EVENT_LOGGER_DEBUG
798 dxs_el_trace_event_read(pDev, pHdr);
799#endif
800
801 /* this is an event header */
802 dxs_handle_event(pDev, pHdr);
803 }
804 else
805 {
806 /* this is a command header */
807 int i;
808 uint32_t *pw32;
809
810 for (i=0, pw32 = (uint32_t *)pHdr; i<msg_len; i++, pw32++)
811 {
812 fifo_put(pDev->cmd_obx_queue, NULL, *pw32);
813 }
814 sem_post(&pDev->obxCmdDataSem);
815 }
816
817 pos1 += (msg_len * 2);
818 words32_remaining -= msg_len;
819
820 /* This implementation works in IRQ edge mode. */
821#if 0
822 /* If the IRQ is edge triggered we have to make sure that the
823 mailbox is empty when we exit the loop. There won't be another IRQ
824 generated if there is still data left in outbox. */
825 if (pos1 >= words16)
826 {
827 DXS_ObxRead(pDev, pDev->dmbx, &words16);
828 if (words16 == 0)
829 break;
830 if (words16 & 1)
831 {
832 /* TODO: is this an error ? */
833 fprintf (stderr, "OutMbx: Odd word count: %d\n", words16);
834 break;
835 }
836 words32 = words16 >> 1;
837 pos1 = 0;
838 }
839#endif
840 }
841 }
842 pthread_exit((void *)DXS_statusOk);
843}
844
845/**
846 Function dxs_outbox_handler_init
847
848 \param pDev - pointer to DXS device structure
849
850 \return
851 - DXS_status_t
852*/
853int32_t dxs_outbox_handler_init(DXS_DEVICE_t *pDev)
854{
855 int32_t ret;
856
857 sem_init(&pDev->obxSemaphore, 0, 0);
858 sem_init(&pDev->obxCmdDataSem, 0, 0);
859
860 pDev->obxThreadStop = 0;
861 pDev->obxDiscardEvents = 1;
862
863 ret = pthread_create(&pDev->obxThread, NULL, dxs_outbox_handler, (void *)pDev);
864 if (ret)
865 {
866 /* error code */
867 DXS_RETURN(DXS_statusThreadCreatError);
868 }
869
870 return DXS_statusOk;
871}
872
873/**
874 Function dxs_outbox_handler_exit
875
876 \param pDev - pointer to DXS device structure
877
878 \return
879 - DXS_status_t
880*/
881int32_t dxs_outbox_handler_exit(DXS_DEVICE_t *pDev)
882{
883 int32_t ret;
884 void *status;
885
886 /* condition to stop */
887 pDev->obxThreadStop = 1;
888
889 /* let the thread run */
890 sem_post (&pDev->obxSemaphore);
891
892 /* wait for the thread to exit */
893 ret = pthread_join(pDev->obxThread, &status);
894 if (ret || status != DXS_statusOk)
895 {
896 /* error code */
897 DXS_RETURN(DXS_statusThreadStopError);
898 }
899
900 sem_destroy(&pDev->obxSemaphore);
901 sem_destroy(&pDev->obxCmdDataSem);
902
903 return ret;
904}
905
906/**
907 Function dxs_outbox_handler_enable
908
909 This enables the event handling. After init the outbox is processed but
910 events are discarded until this function is called.
911
912 \param pDev - pointer to DXS device structure
913*/
914void dxs_outbox_handler_enable(DXS_DEVICE_t *pDev)
915{
916 /* From now on process all events. */
917 pDev->obxDiscardEvents = 0;
918}