linux/drivers/isdn/hardware/eicon/debug.c
<<
>>
Prefs
   1#include "platform.h"
   2#include "pc.h"
   3#include "di_defs.h"
   4#include "debug_if.h"
   5#include "divasync.h"
   6#include "kst_ifc.h"
   7#include "maintidi.h"
   8#include "man_defs.h"
   9
  10/*
  11  LOCALS
  12*/
  13#define DBG_MAGIC (0x47114711L)
  14
  15static void DI_register(void *arg);
  16static void DI_deregister(pDbgHandle hDbg);
  17static void DI_format(int do_lock, word id, int type, char *format, va_list argument_list);
  18static void DI_format_locked(word id, int type, char *format, va_list argument_list);
  19static void DI_format_old(word id, char *format, va_list ap) { }
  20static void DiProcessEventLog(unsigned short id, unsigned long msgID, va_list ap) { }
  21static void single_p(byte *P, word *PLength, byte Id);
  22static void diva_maint_xdi_cb(ENTITY *e);
  23static word SuperTraceCreateReadReq(byte *P, const char *path);
  24static int diva_mnt_cmp_nmbr(const char *nmbr);
  25static void diva_free_dma_descriptor(IDI_CALL request, int nr);
  26static int diva_get_dma_descriptor(IDI_CALL request, dword *dma_magic);
  27void diva_mnt_internal_dprintf(dword drv_id, dword type, char *p, ...);
  28
  29static dword MaxDumpSize = 256;
  30static dword MaxXlogSize = 2 + 128;
  31static char  TraceFilter[DIVA_MAX_SELECTIVE_FILTER_LENGTH + 1];
  32static int TraceFilterIdent   = -1;
  33static int TraceFilterChannel = -1;
  34
  35typedef struct _diva_maint_client {
  36        dword       sec;
  37        dword       usec;
  38        pDbgHandle  hDbg;
  39        char        drvName[128];
  40        dword       dbgMask;
  41        dword       last_dbgMask;
  42        IDI_CALL    request;
  43        _DbgHandle_ Dbg;
  44        int         logical;
  45        int         channels;
  46        diva_strace_library_interface_t *pIdiLib;
  47        BUFFERS     XData;
  48        char        xbuffer[2048 + 512];
  49        byte        *pmem;
  50        int         request_pending;
  51        int         dma_handle;
  52} diva_maint_client_t;
  53static diva_maint_client_t clients[MAX_DESCRIPTORS];
  54
  55static void diva_change_management_debug_mask(diva_maint_client_t *pC, dword old_mask);
  56
  57static void diva_maint_error(void *user_context,
  58                             diva_strace_library_interface_t *hLib,
  59                             int Adapter,
  60                             int error,
  61                             const char *file,
  62                             int line);
  63static void diva_maint_state_change_notify(void *user_context,
  64                                           diva_strace_library_interface_t *hLib,
  65                                           int Adapter,
  66                                           diva_trace_line_state_t *channel,
  67                                           int notify_subject);
  68static void diva_maint_trace_notify(void *user_context,
  69                                    diva_strace_library_interface_t *hLib,
  70                                    int Adapter,
  71                                    void *xlog_buffer,
  72                                    int length);
  73
  74
  75
  76typedef struct MSG_QUEUE {
  77        dword   Size;           /* total size of queue (constant)       */
  78        byte    *Base;          /* lowest address (constant)            */
  79        byte    *High;          /* Base + Size (constant)               */
  80        byte    *Head;          /* first message in queue (if any)      */
  81        byte    *Tail;          /* first free position                  */
  82        byte    *Wrap;          /* current wraparound position          */
  83        dword   Count;          /* current no of bytes in queue         */
  84} MSG_QUEUE;
  85
  86typedef struct MSG_HEAD {
  87        volatile dword  Size;           /* size of data following MSG_HEAD      */
  88#define MSG_INCOMPLETE  0x8000  /* ored to Size until queueCompleteMsg  */
  89} MSG_HEAD;
  90
  91#define queueCompleteMsg(p) do { ((MSG_HEAD *)p - 1)->Size &= ~MSG_INCOMPLETE; } while (0)
  92#define queueCount(q)   ((q)->Count)
  93#define MSG_NEED(size)                                                  \
  94        ((sizeof(MSG_HEAD) + size + sizeof(dword) - 1) & ~(sizeof(dword) - 1))
  95
  96static void queueInit(MSG_QUEUE *Q, byte *Buffer, dword sizeBuffer) {
  97        Q->Size = sizeBuffer;
  98        Q->Base = Q->Head = Q->Tail = Buffer;
  99        Q->High = Buffer + sizeBuffer;
 100        Q->Wrap = NULL;
 101        Q->Count = 0;
 102}
 103
 104static byte *queueAllocMsg(MSG_QUEUE *Q, word size) {
 105        /* Allocate 'size' bytes at tail of queue which will be filled later
 106         * directly with callers own message header info and/or message.
 107         * An 'alloced' message is marked incomplete by oring the 'Size' field
 108         * with MSG_INCOMPLETE.
 109         * This must be reset via queueCompleteMsg() after the message is filled.
 110         * As long as a message is marked incomplete queuePeekMsg() will return
 111         * a 'queue empty' condition when it reaches such a message.  */
 112
 113        MSG_HEAD *Msg;
 114        word need = MSG_NEED(size);
 115
 116        if (Q->Tail == Q->Head) {
 117                if (Q->Wrap || need > Q->Size) {
 118                        return NULL; /* full */
 119                }
 120                goto alloc; /* empty */
 121        }
 122
 123        if (Q->Tail > Q->Head) {
 124                if (Q->Tail + need <= Q->High) goto alloc; /* append */
 125                if (Q->Base + need > Q->Head) {
 126                        return NULL; /* too much */
 127                }
 128                /* wraparound the queue (but not the message) */
 129                Q->Wrap = Q->Tail;
 130                Q->Tail = Q->Base;
 131                goto alloc;
 132        }
 133
 134        if (Q->Tail + need > Q->Head) {
 135                return NULL; /* too much */
 136        }
 137
 138alloc:
 139        Msg = (MSG_HEAD *)Q->Tail;
 140
 141        Msg->Size = size | MSG_INCOMPLETE;
 142
 143        Q->Tail  += need;
 144        Q->Count += size;
 145
 146
 147
 148        return ((byte *)(Msg + 1));
 149}
 150
 151static void queueFreeMsg(MSG_QUEUE *Q) {
 152/* Free the message at head of queue */
 153
 154        word size = ((MSG_HEAD *)Q->Head)->Size & ~MSG_INCOMPLETE;
 155
 156        Q->Head  += MSG_NEED(size);
 157        Q->Count -= size;
 158
 159        if (Q->Wrap) {
 160                if (Q->Head >= Q->Wrap) {
 161                        Q->Head = Q->Base;
 162                        Q->Wrap = NULL;
 163                }
 164        } else if (Q->Head >= Q->Tail) {
 165                Q->Head = Q->Tail = Q->Base;
 166        }
 167}
 168
 169static byte *queuePeekMsg(MSG_QUEUE *Q, word *size) {
 170        /* Show the first valid message in queue BUT DON'T free the message.
 171         * After looking on the message contents it can be freed queueFreeMsg()
 172         * or simply remain in message queue.  */
 173
 174        MSG_HEAD *Msg = (MSG_HEAD *)Q->Head;
 175
 176        if (((byte *)Msg == Q->Tail && !Q->Wrap) ||
 177            (Msg->Size & MSG_INCOMPLETE)) {
 178                return NULL;
 179        } else {
 180                *size = Msg->Size;
 181                return ((byte *)(Msg + 1));
 182        }
 183}
 184
 185/*
 186  Message queue header
 187*/
 188static MSG_QUEUE *dbg_queue;
 189static byte *dbg_base;
 190static int                 external_dbg_queue;
 191static diva_os_spin_lock_t dbg_q_lock;
 192static diva_os_spin_lock_t dbg_adapter_lock;
 193static int                 dbg_q_busy;
 194static volatile dword      dbg_sequence;
 195
 196/*
 197  INTERFACE:
 198  Initialize run time queue structures.
 199  base:    base of the message queue
 200  length:  length of the message queue
 201  do_init: perfor queue reset
 202
 203  return:  zero on success, -1 on error
 204*/
 205int diva_maint_init(byte *base, unsigned long length, int do_init) {
 206        if (dbg_queue || (!base) || (length < (4096 * 4))) {
 207                return (-1);
 208        }
 209
 210        TraceFilter[0]     =  0;
 211        TraceFilterIdent   = -1;
 212        TraceFilterChannel = -1;
 213
 214        dbg_base = base;
 215
 216        *(dword *)base  = (dword)DBG_MAGIC; /* Store Magic */
 217        base   += sizeof(dword);
 218        length -= sizeof(dword);
 219
 220        *(dword *)base = 2048; /* Extension Field Length */
 221        base   += sizeof(dword);
 222        length -= sizeof(dword);
 223
 224        strcpy(base, "KERNEL MODE BUFFER\n");
 225        base   += 2048;
 226        length -= 2048;
 227
 228        *(dword *)base = 0; /* Terminate extension */
 229        base   += sizeof(dword);
 230        length -= sizeof(dword);
 231
 232        *(void **)base  =  (void *)(base + sizeof(void *)); /* Store Base  */
 233        base   += sizeof(void *);
 234        length -= sizeof(void *);
 235
 236        dbg_queue = (MSG_QUEUE *)base;
 237        queueInit(dbg_queue, base + sizeof(MSG_QUEUE), length - sizeof(MSG_QUEUE) - 512);
 238        external_dbg_queue = 0;
 239
 240        if (!do_init) {
 241                external_dbg_queue = 1; /* memory was located on the external device */
 242        }
 243
 244
 245        if (diva_os_initialize_spin_lock(&dbg_q_lock, "dbg_init")) {
 246                dbg_queue = NULL;
 247                dbg_base = NULL;
 248                external_dbg_queue = 0;
 249                return (-1);
 250        }
 251
 252        if (diva_os_initialize_spin_lock(&dbg_adapter_lock, "dbg_init")) {
 253                diva_os_destroy_spin_lock(&dbg_q_lock, "dbg_init");
 254                dbg_queue = NULL;
 255                dbg_base = NULL;
 256                external_dbg_queue = 0;
 257                return (-1);
 258        }
 259
 260        return (0);
 261}
 262
 263/*
 264  INTERFACE:
 265  Finit at unload time
 266  return address of internal queue or zero if queue
 267  was external
 268*/
 269void *diva_maint_finit(void) {
 270        void *ret = (void *)dbg_base;
 271        int i;
 272
 273        dbg_queue = NULL;
 274        dbg_base  = NULL;
 275
 276        if (ret) {
 277                diva_os_destroy_spin_lock(&dbg_q_lock, "dbg_finit");
 278                diva_os_destroy_spin_lock(&dbg_adapter_lock, "dbg_finit");
 279        }
 280
 281        if (external_dbg_queue) {
 282                ret = NULL;
 283        }
 284        external_dbg_queue = 0;
 285
 286        for (i = 1; i < ARRAY_SIZE(clients); i++) {
 287                if (clients[i].pmem) {
 288                        diva_os_free(0, clients[i].pmem);
 289                }
 290        }
 291
 292        return (ret);
 293}
 294
 295/*
 296  INTERFACE:
 297  Return amount of messages in debug queue
 298*/
 299dword diva_dbg_q_length(void) {
 300        return (dbg_queue ? queueCount(dbg_queue)       : 0);
 301}
 302
 303/*
 304  INTERFACE:
 305  Lock message queue and return the pointer to the first
 306  entry.
 307*/
 308diva_dbg_entry_head_t *diva_maint_get_message(word *size,
 309                                              diva_os_spin_lock_magic_t *old_irql) {
 310        diva_dbg_entry_head_t *pmsg = NULL;
 311
 312        diva_os_enter_spin_lock(&dbg_q_lock, old_irql, "read");
 313        if (dbg_q_busy) {
 314                diva_os_leave_spin_lock(&dbg_q_lock, old_irql, "read_busy");
 315                return NULL;
 316        }
 317        dbg_q_busy = 1;
 318
 319        if (!(pmsg = (diva_dbg_entry_head_t *)queuePeekMsg(dbg_queue, size))) {
 320                dbg_q_busy = 0;
 321                diva_os_leave_spin_lock(&dbg_q_lock, old_irql, "read_empty");
 322        }
 323
 324        return (pmsg);
 325}
 326
 327/*
 328  INTERFACE:
 329  acknowledge last message and unlock queue
 330*/
 331void diva_maint_ack_message(int do_release,
 332                            diva_os_spin_lock_magic_t *old_irql) {
 333        if (!dbg_q_busy) {
 334                return;
 335        }
 336        if (do_release) {
 337                queueFreeMsg(dbg_queue);
 338        }
 339        dbg_q_busy = 0;
 340        diva_os_leave_spin_lock(&dbg_q_lock, old_irql, "read_ack");
 341}
 342
 343
 344/*
 345  INTERFACE:
 346  PRT COMP function used to register
 347  with MAINT adapter or log in compatibility
 348  mode in case older driver version is connected too
 349*/
 350void diva_maint_prtComp(char *format, ...) {
 351        void    *hDbg;
 352        va_list ap;
 353
 354        if (!format)
 355                return;
 356
 357        va_start(ap, format);
 358
 359        /*
 360          register to new log driver functions
 361        */
 362        if ((format[0] == 0) && ((unsigned char)format[1] == 255)) {
 363                hDbg = va_arg(ap, void *); /* ptr to DbgHandle */
 364                DI_register(hDbg);
 365        }
 366
 367        va_end(ap);
 368}
 369
 370static void DI_register(void *arg) {
 371        diva_os_spin_lock_magic_t old_irql;
 372        dword sec, usec;
 373        pDbgHandle      hDbg;
 374        int id, free_id = -1, best_id = 0;
 375
 376        diva_os_get_time(&sec, &usec);
 377
 378        hDbg = (pDbgHandle)arg;
 379        /*
 380          Check for bad args, specially for the old obsolete debug handle
 381        */
 382        if ((hDbg == NULL) ||
 383            ((hDbg->id == 0) && (((_OldDbgHandle_ *)hDbg)->id == -1)) ||
 384            (hDbg->Registered != 0)) {
 385                return;
 386        }
 387
 388        diva_os_enter_spin_lock(&dbg_q_lock, &old_irql, "register");
 389
 390        for (id = 1; id < ARRAY_SIZE(clients); id++) {
 391                if (clients[id].hDbg == hDbg) {
 392                        /*
 393                          driver already registered
 394                        */
 395                        diva_os_leave_spin_lock(&dbg_q_lock, &old_irql, "register");
 396                        return;
 397                }
 398                if (clients[id].hDbg) { /* slot is busy */
 399                        continue;
 400                }
 401                free_id = id;
 402                if (!strcmp(clients[id].drvName, hDbg->drvName)) {
 403                        /*
 404                          This driver was already registered with this name
 405                          and slot is still free - reuse it
 406                        */
 407                        best_id = 1;
 408                        break;
 409                }
 410                if (!clients[id].hDbg) { /* slot is busy */
 411                        break;
 412                }
 413        }
 414
 415        if (free_id != -1) {
 416                diva_dbg_entry_head_t *pmsg = NULL;
 417                int len;
 418                char tmp[256];
 419                word size;
 420
 421                /*
 422                  Register new driver with id == free_id
 423                */
 424                clients[free_id].hDbg = hDbg;
 425                clients[free_id].sec  = sec;
 426                clients[free_id].usec = usec;
 427                strcpy(clients[free_id].drvName, hDbg->drvName);
 428
 429                clients[free_id].dbgMask = hDbg->dbgMask;
 430                if (best_id) {
 431                        hDbg->dbgMask |= clients[free_id].last_dbgMask;
 432                } else {
 433                        clients[free_id].last_dbgMask = 0;
 434                }
 435
 436                hDbg->Registered = DBG_HANDLE_REG_NEW;
 437                hDbg->id         = (byte)free_id;
 438                hDbg->dbg_end    = DI_deregister;
 439                hDbg->dbg_prt    = DI_format_locked;
 440                hDbg->dbg_ev     = DiProcessEventLog;
 441                hDbg->dbg_irq    = DI_format_locked;
 442                if (hDbg->Version > 0) {
 443                        hDbg->dbg_old  = DI_format_old;
 444                }
 445                hDbg->next       = (pDbgHandle)DBG_MAGIC;
 446
 447                /*
 448                  Log driver register, MAINT driver ID is '0'
 449                */
 450                len = sprintf(tmp, "DIMAINT - drv # %d = '%s' registered",
 451                              free_id, hDbg->drvName);
 452
 453                while (!(pmsg = (diva_dbg_entry_head_t *)queueAllocMsg(dbg_queue,
 454                                                                       (word)(len + 1 + sizeof(*pmsg))))) {
 455                        if ((pmsg = (diva_dbg_entry_head_t *)queuePeekMsg(dbg_queue, &size))) {
 456                                queueFreeMsg(dbg_queue);
 457                        } else {
 458                                break;
 459                        }
 460                }
 461
 462                if (pmsg) {
 463                        pmsg->sequence    = dbg_sequence++;
 464                        pmsg->time_sec    = sec;
 465                        pmsg->time_usec   = usec;
 466                        pmsg->facility    = MSG_TYPE_STRING;
 467                        pmsg->dli         = DLI_REG;
 468                        pmsg->drv_id      = 0; /* id 0 - DIMAINT */
 469                        pmsg->di_cpu      = 0;
 470                        pmsg->data_length = len + 1;
 471
 472                        memcpy(&pmsg[1], tmp, len + 1);
 473                        queueCompleteMsg(pmsg);
 474                        diva_maint_wakeup_read();
 475                }
 476        }
 477
 478        diva_os_leave_spin_lock(&dbg_q_lock, &old_irql, "register");
 479}
 480
 481static void DI_deregister(pDbgHandle hDbg) {
 482        diva_os_spin_lock_magic_t old_irql, old_irql1;
 483        dword sec, usec;
 484        int i;
 485        word size;
 486        byte *pmem = NULL;
 487
 488        diva_os_get_time(&sec, &usec);
 489
 490        diva_os_enter_spin_lock(&dbg_adapter_lock, &old_irql1, "read");
 491        diva_os_enter_spin_lock(&dbg_q_lock, &old_irql, "read");
 492
 493        for (i = 1; i < ARRAY_SIZE(clients); i++) {
 494                if (clients[i].hDbg == hDbg) {
 495                        diva_dbg_entry_head_t *pmsg;
 496                        char tmp[256];
 497                        int len;
 498
 499                        clients[i].hDbg = NULL;
 500
 501                        hDbg->id       = -1;
 502                        hDbg->dbgMask  = 0;
 503                        hDbg->dbg_end  = NULL;
 504                        hDbg->dbg_prt  = NULL;
 505                        hDbg->dbg_irq  = NULL;
 506                        if (hDbg->Version > 0)
 507                                hDbg->dbg_old = NULL;
 508                        hDbg->Registered = 0;
 509                        hDbg->next     = NULL;
 510
 511                        if (clients[i].pIdiLib) {
 512                                (*(clients[i].pIdiLib->DivaSTraceLibraryFinit))(clients[i].pIdiLib->hLib);
 513                                clients[i].pIdiLib = NULL;
 514
 515                                pmem = clients[i].pmem;
 516                                clients[i].pmem = NULL;
 517                        }
 518
 519                        /*
 520                          Log driver register, MAINT driver ID is '0'
 521                        */
 522                        len = sprintf(tmp, "DIMAINT - drv # %d = '%s' de-registered",
 523                                      i, hDbg->drvName);
 524
 525                        while (!(pmsg = (diva_dbg_entry_head_t *)queueAllocMsg(dbg_queue,
 526                                                                              (word)(len + 1 + sizeof(*pmsg))))) {
 527                                if ((pmsg = (diva_dbg_entry_head_t *)queuePeekMsg(dbg_queue, &size))) {
 528                                        queueFreeMsg(dbg_queue);
 529                                } else {
 530                                        break;
 531                                }
 532                        }
 533
 534                        if (pmsg) {
 535                                pmsg->sequence    = dbg_sequence++;
 536                                pmsg->time_sec    = sec;
 537                                pmsg->time_usec   = usec;
 538                                pmsg->facility    = MSG_TYPE_STRING;
 539                                pmsg->dli         = DLI_REG;
 540                                pmsg->drv_id      = 0; /* id 0 - DIMAINT */
 541                                pmsg->di_cpu      = 0;
 542                                pmsg->data_length = len + 1;
 543
 544                                memcpy(&pmsg[1], tmp, len + 1);
 545                                queueCompleteMsg(pmsg);
 546                                diva_maint_wakeup_read();
 547                        }
 548
 549                        break;
 550                }
 551        }
 552
 553        diva_os_leave_spin_lock(&dbg_q_lock, &old_irql, "read_ack");
 554        diva_os_leave_spin_lock(&dbg_adapter_lock, &old_irql1, "read_ack");
 555
 556        if (pmem) {
 557                diva_os_free(0, pmem);
 558        }
 559}
 560
 561static void DI_format_locked(unsigned short id,
 562                             int type,
 563                             char *format,
 564                             va_list argument_list) {
 565        DI_format(1, id, type, format, argument_list);
 566}
 567
 568static void DI_format(int do_lock,
 569                      unsigned short id,
 570                      int type,
 571                      char *format,
 572                      va_list ap) {
 573        diva_os_spin_lock_magic_t old_irql;
 574        dword sec, usec;
 575        diva_dbg_entry_head_t *pmsg = NULL;
 576        dword length;
 577        word size;
 578        static char fmtBuf[MSG_FRAME_MAX_SIZE + sizeof(*pmsg) + 1];
 579        char          *data;
 580        unsigned short code;
 581
 582        if (diva_os_in_irq()) {
 583                dbg_sequence++;
 584                return;
 585        }
 586
 587        if ((!format) ||
 588            ((TraceFilter[0] != 0) && ((TraceFilterIdent < 0) || (TraceFilterChannel < 0)))) {
 589                return;
 590        }
 591
 592
 593
 594        diva_os_get_time(&sec, &usec);
 595
 596        if (do_lock) {
 597                diva_os_enter_spin_lock(&dbg_q_lock, &old_irql, "format");
 598        }
 599
 600        switch (type) {
 601        case DLI_MXLOG:
 602        case DLI_BLK:
 603        case DLI_SEND:
 604        case DLI_RECV:
 605                if (!(length = va_arg(ap, unsigned long))) {
 606                        break;
 607                }
 608                if (length > MaxDumpSize) {
 609                        length = MaxDumpSize;
 610                }
 611                while (!(pmsg = (diva_dbg_entry_head_t *)queueAllocMsg(dbg_queue,
 612                                                                       (word)length + sizeof(*pmsg)))) {
 613                        if ((pmsg = (diva_dbg_entry_head_t *)queuePeekMsg(dbg_queue, &size))) {
 614                                queueFreeMsg(dbg_queue);
 615                        } else {
 616                                break;
 617                        }
 618                }
 619                if (pmsg) {
 620                        memcpy(&pmsg[1], format, length);
 621                        pmsg->sequence    = dbg_sequence++;
 622                        pmsg->time_sec    = sec;
 623                        pmsg->time_usec   = usec;
 624                        pmsg->facility    = MSG_TYPE_BINARY;
 625                        pmsg->dli         = type; /* DLI_XXX */
 626                        pmsg->drv_id      = id;   /* driver MAINT id */
 627                        pmsg->di_cpu      = 0;
 628                        pmsg->data_length = length;
 629                        queueCompleteMsg(pmsg);
 630                }
 631                break;
 632
 633        case DLI_XLOG: {
 634                byte *p;
 635                data    = va_arg(ap, char *);
 636                code    = (unsigned short)va_arg(ap, unsigned int);
 637                length  = (unsigned long)va_arg(ap, unsigned int);
 638
 639                if (length > MaxXlogSize)
 640                        length = MaxXlogSize;
 641
 642                while (!(pmsg = (diva_dbg_entry_head_t *)queueAllocMsg(dbg_queue,
 643                                                                      (word)length + sizeof(*pmsg) + 2))) {
 644                        if ((pmsg = (diva_dbg_entry_head_t *)queuePeekMsg(dbg_queue, &size))) {
 645                                queueFreeMsg(dbg_queue);
 646                        } else {
 647                                break;
 648                        }
 649                }
 650                if (pmsg) {
 651                        p = (byte *)&pmsg[1];
 652                        p[0] = (char)(code);
 653                        p[1] = (char)(code >> 8);
 654                        if (data && length) {
 655                                memcpy(&p[2], &data[0], length);
 656                        }
 657                        length += 2;
 658
 659                        pmsg->sequence    = dbg_sequence++;
 660                        pmsg->time_sec    = sec;
 661                        pmsg->time_usec   = usec;
 662                        pmsg->facility    = MSG_TYPE_BINARY;
 663                        pmsg->dli         = type; /* DLI_XXX */
 664                        pmsg->drv_id      = id;   /* driver MAINT id */
 665                        pmsg->di_cpu      = 0;
 666                        pmsg->data_length = length;
 667                        queueCompleteMsg(pmsg);
 668                }
 669        } break;
 670
 671        case DLI_LOG:
 672        case DLI_FTL:
 673        case DLI_ERR:
 674        case DLI_TRC:
 675        case DLI_REG:
 676        case DLI_MEM:
 677        case DLI_SPL:
 678        case DLI_IRP:
 679        case DLI_TIM:
 680        case DLI_TAPI:
 681        case DLI_NDIS:
 682        case DLI_CONN:
 683        case DLI_STAT:
 684        case DLI_PRV0:
 685        case DLI_PRV1:
 686        case DLI_PRV2:
 687        case DLI_PRV3:
 688                if ((length = (unsigned long)vsprintf(&fmtBuf[0], format, ap)) > 0) {
 689                        length += (sizeof(*pmsg) + 1);
 690
 691                        while (!(pmsg = (diva_dbg_entry_head_t *)queueAllocMsg(dbg_queue,
 692                                                                               (word)length))) {
 693                                if ((pmsg = (diva_dbg_entry_head_t *)queuePeekMsg(dbg_queue, &size))) {
 694                                        queueFreeMsg(dbg_queue);
 695                                } else {
 696                                        break;
 697                                }
 698                        }
 699
 700                        pmsg->sequence    = dbg_sequence++;
 701                        pmsg->time_sec    = sec;
 702                        pmsg->time_usec   = usec;
 703                        pmsg->facility    = MSG_TYPE_STRING;
 704                        pmsg->dli         = type; /* DLI_XXX */
 705                        pmsg->drv_id      = id;   /* driver MAINT id */
 706                        pmsg->di_cpu      = 0;
 707                        pmsg->data_length = length - sizeof(*pmsg);
 708
 709                        memcpy(&pmsg[1], fmtBuf, pmsg->data_length);
 710                        queueCompleteMsg(pmsg);
 711                }
 712                break;
 713
 714        } /* switch type */
 715
 716
 717        if (queueCount(dbg_queue)) {
 718                diva_maint_wakeup_read();
 719        }
 720
 721        if (do_lock) {
 722                diva_os_leave_spin_lock(&dbg_q_lock, &old_irql, "format");
 723        }
 724}
 725
 726/*
 727  Write driver ID and driver revision to callers buffer
 728*/
 729int diva_get_driver_info(dword id, byte *data, int data_length) {
 730        diva_os_spin_lock_magic_t old_irql;
 731        byte *p = data;
 732        int to_copy;
 733
 734        if (!data || !id || (data_length < 17) ||
 735            (id >= ARRAY_SIZE(clients))) {
 736                return (-1);
 737        }
 738
 739        diva_os_enter_spin_lock(&dbg_q_lock, &old_irql, "driver info");
 740
 741        if (clients[id].hDbg) {
 742                *p++ = 1;
 743                *p++ = (byte)clients[id].sec; /* save seconds */
 744                *p++ = (byte)(clients[id].sec >>  8);
 745                *p++ = (byte)(clients[id].sec >> 16);
 746                *p++ = (byte)(clients[id].sec >> 24);
 747
 748                *p++ = (byte)(clients[id].usec / 1000); /* save mseconds */
 749                *p++ = (byte)((clients[id].usec / 1000) >>  8);
 750                *p++ = (byte)((clients[id].usec / 1000) >> 16);
 751                *p++ = (byte)((clients[id].usec / 1000) >> 24);
 752
 753                data_length -= 9;
 754
 755                if ((to_copy = min(strlen(clients[id].drvName), (size_t)(data_length - 1)))) {
 756                        memcpy(p, clients[id].drvName, to_copy);
 757                        p += to_copy;
 758                        data_length -= to_copy;
 759                        if ((data_length >= 4) && clients[id].hDbg->drvTag[0]) {
 760                                *p++ = '(';
 761                                data_length -= 1;
 762                                if ((to_copy = min(strlen(clients[id].hDbg->drvTag), (size_t)(data_length - 2)))) {
 763                                        memcpy(p, clients[id].hDbg->drvTag, to_copy);
 764                                        p += to_copy;
 765                                        data_length -= to_copy;
 766                                        if (data_length >= 2) {
 767                                                *p++ = ')';
 768                                                data_length--;
 769                                        }
 770                                }
 771                        }
 772                }
 773        }
 774        *p++ = 0;
 775
 776        diva_os_leave_spin_lock(&dbg_q_lock, &old_irql, "driver info");
 777
 778        return (p - data);
 779}
 780
 781int diva_get_driver_dbg_mask(dword id, byte *data) {
 782        diva_os_spin_lock_magic_t old_irql;
 783        int ret = -1;
 784
 785        if (!data || !id || (id >= ARRAY_SIZE(clients))) {
 786                return (-1);
 787        }
 788        diva_os_enter_spin_lock(&dbg_q_lock, &old_irql, "driver info");
 789
 790        if (clients[id].hDbg) {
 791                ret = 4;
 792                *data++ = (byte)(clients[id].hDbg->dbgMask);
 793                *data++ = (byte)(clients[id].hDbg->dbgMask >>  8);
 794                *data++ = (byte)(clients[id].hDbg->dbgMask >> 16);
 795                *data++ = (byte)(clients[id].hDbg->dbgMask >> 24);
 796        }
 797
 798        diva_os_leave_spin_lock(&dbg_q_lock, &old_irql, "driver info");
 799
 800        return (ret);
 801}
 802
 803int diva_set_driver_dbg_mask(dword id, dword mask) {
 804        diva_os_spin_lock_magic_t old_irql, old_irql1;
 805        int ret = -1;
 806
 807
 808        if (!id || (id >= ARRAY_SIZE(clients))) {
 809                return (-1);
 810        }
 811
 812        diva_os_enter_spin_lock(&dbg_adapter_lock, &old_irql1, "dbg mask");
 813        diva_os_enter_spin_lock(&dbg_q_lock, &old_irql, "dbg mask");
 814
 815        if (clients[id].hDbg) {
 816                dword old_mask = clients[id].hDbg->dbgMask;
 817                mask &= 0x7fffffff;
 818                clients[id].hDbg->dbgMask = mask;
 819                clients[id].last_dbgMask = (clients[id].hDbg->dbgMask | clients[id].dbgMask);
 820                ret = 4;
 821                diva_change_management_debug_mask(&clients[id], old_mask);
 822        }
 823
 824
 825        diva_os_leave_spin_lock(&dbg_q_lock, &old_irql, "dbg mask");
 826
 827        if (clients[id].request_pending) {
 828                clients[id].request_pending = 0;
 829                (*(clients[id].request))((ENTITY *)(*(clients[id].pIdiLib->DivaSTraceGetHandle))(clients[id].pIdiLib->hLib));
 830        }
 831
 832        diva_os_leave_spin_lock(&dbg_adapter_lock, &old_irql1, "dbg mask");
 833
 834        return (ret);
 835}
 836
 837static int diva_get_idi_adapter_info(IDI_CALL request, dword *serial, dword *logical) {
 838        IDI_SYNC_REQ sync_req;
 839
 840        sync_req.xdi_logical_adapter_number.Req = 0;
 841        sync_req.xdi_logical_adapter_number.Rc = IDI_SYNC_REQ_XDI_GET_LOGICAL_ADAPTER_NUMBER;
 842        (*request)((ENTITY *)&sync_req);
 843        *logical = sync_req.xdi_logical_adapter_number.info.logical_adapter_number;
 844
 845        sync_req.GetSerial.Req = 0;
 846        sync_req.GetSerial.Rc = IDI_SYNC_REQ_GET_SERIAL;
 847        sync_req.GetSerial.serial = 0;
 848        (*request)((ENTITY *)&sync_req);
 849        *serial = sync_req.GetSerial.serial;
 850
 851        return (0);
 852}
 853
 854/*
 855  Register XDI adapter as MAINT compatible driver
 856*/
 857void diva_mnt_add_xdi_adapter(const DESCRIPTOR *d) {
 858        diva_os_spin_lock_magic_t old_irql, old_irql1;
 859        dword sec, usec, logical, serial, org_mask;
 860        int id, free_id = -1;
 861        char tmp[128];
 862        diva_dbg_entry_head_t *pmsg = NULL;
 863        int len;
 864        word size;
 865        byte *pmem;
 866
 867        diva_os_get_time(&sec, &usec);
 868        diva_get_idi_adapter_info(d->request, &serial, &logical);
 869        if (serial & 0xff000000) {
 870                sprintf(tmp, "ADAPTER:%d SN:%u-%d",
 871                        (int)logical,
 872                        serial & 0x00ffffff,
 873                        (byte)(((serial & 0xff000000) >> 24) + 1));
 874        } else {
 875                sprintf(tmp, "ADAPTER:%d SN:%u", (int)logical, serial);
 876        }
 877
 878        if (!(pmem = diva_os_malloc(0, DivaSTraceGetMemotyRequirement(d->channels)))) {
 879                return;
 880        }
 881        memset(pmem, 0x00, DivaSTraceGetMemotyRequirement(d->channels));
 882
 883        diva_os_enter_spin_lock(&dbg_adapter_lock, &old_irql1, "register");
 884        diva_os_enter_spin_lock(&dbg_q_lock, &old_irql, "register");
 885
 886        for (id = 1; id < ARRAY_SIZE(clients); id++) {
 887                if (clients[id].hDbg && (clients[id].request == d->request)) {
 888                        diva_os_leave_spin_lock(&dbg_q_lock, &old_irql, "register");
 889                        diva_os_leave_spin_lock(&dbg_adapter_lock, &old_irql1, "register");
 890                        diva_os_free(0, pmem);
 891                        return;
 892                }
 893                if (clients[id].hDbg) { /* slot is busy */
 894                        continue;
 895                }
 896                if (free_id < 0) {
 897                        free_id = id;
 898                }
 899                if (!strcmp(clients[id].drvName, tmp)) {
 900                        /*
 901                          This driver was already registered with this name
 902                          and slot is still free - reuse it
 903                        */
 904                        free_id = id;
 905                        break;
 906                }
 907        }
 908
 909        if (free_id < 0) {
 910                diva_os_leave_spin_lock(&dbg_q_lock, &old_irql, "register");
 911                diva_os_leave_spin_lock(&dbg_adapter_lock, &old_irql1, "register");
 912                diva_os_free(0, pmem);
 913                return;
 914        }
 915
 916        id = free_id;
 917        clients[id].request  = d->request;
 918        clients[id].request_pending = 0;
 919        clients[id].hDbg     = &clients[id].Dbg;
 920        clients[id].sec      = sec;
 921        clients[id].usec     = usec;
 922        strcpy(clients[id].drvName,     tmp);
 923        strcpy(clients[id].Dbg.drvName, tmp);
 924        clients[id].Dbg.drvTag[0] = 0;
 925        clients[id].logical  = (int)logical;
 926        clients[id].channels = (int)d->channels;
 927        clients[id].dma_handle = -1;
 928
 929        clients[id].Dbg.dbgMask    = 0;
 930        clients[id].dbgMask        = clients[id].Dbg.dbgMask;
 931        if (id) {
 932                clients[id].Dbg.dbgMask |= clients[free_id].last_dbgMask;
 933        } else {
 934                clients[id].last_dbgMask = 0;
 935        }
 936        clients[id].Dbg.Registered = DBG_HANDLE_REG_NEW;
 937        clients[id].Dbg.id         = (byte)id;
 938        clients[id].Dbg.dbg_end    = DI_deregister;
 939        clients[id].Dbg.dbg_prt    = DI_format_locked;
 940        clients[id].Dbg.dbg_ev     = DiProcessEventLog;
 941        clients[id].Dbg.dbg_irq    = DI_format_locked;
 942        clients[id].Dbg.next       = (pDbgHandle)DBG_MAGIC;
 943
 944        {
 945                diva_trace_library_user_interface_t diva_maint_user_ifc = { &clients[id],
 946                                                                            diva_maint_state_change_notify,
 947                                                                            diva_maint_trace_notify,
 948                                                                            diva_maint_error };
 949
 950                /*
 951                  Attach to adapter management interface
 952                */
 953                if ((clients[id].pIdiLib =
 954                     DivaSTraceLibraryCreateInstance((int)logical, &diva_maint_user_ifc, pmem))) {
 955                        if (((*(clients[id].pIdiLib->DivaSTraceLibraryStart))(clients[id].pIdiLib->hLib))) {
 956                                diva_mnt_internal_dprintf(0, DLI_ERR, "Adapter(%d) Start failed", (int)logical);
 957                                (*(clients[id].pIdiLib->DivaSTraceLibraryFinit))(clients[id].pIdiLib->hLib);
 958                                clients[id].pIdiLib = NULL;
 959                        }
 960                } else {
 961                        diva_mnt_internal_dprintf(0, DLI_ERR, "A(%d) management init failed", (int)logical);
 962                }
 963        }
 964
 965        if (!clients[id].pIdiLib) {
 966                clients[id].request = NULL;
 967                clients[id].request_pending = 0;
 968                clients[id].hDbg    = NULL;
 969                diva_os_leave_spin_lock(&dbg_q_lock, &old_irql, "register");
 970                diva_os_leave_spin_lock(&dbg_adapter_lock, &old_irql1, "register");
 971                diva_os_free(0, pmem);
 972                return;
 973        }
 974
 975        /*
 976          Log driver register, MAINT driver ID is '0'
 977        */
 978        len = sprintf(tmp, "DIMAINT - drv # %d = '%s' registered",
 979                      id, clients[id].Dbg.drvName);
 980
 981        while (!(pmsg = (diva_dbg_entry_head_t *)queueAllocMsg(dbg_queue,
 982                                                               (word)(len + 1 + sizeof(*pmsg))))) {
 983                if ((pmsg = (diva_dbg_entry_head_t *)queuePeekMsg(dbg_queue, &size))) {
 984                        queueFreeMsg(dbg_queue);
 985                } else {
 986                        break;
 987                }
 988        }
 989
 990        if (pmsg) {
 991                pmsg->sequence    = dbg_sequence++;
 992                pmsg->time_sec    = sec;
 993                pmsg->time_usec   = usec;
 994                pmsg->facility    = MSG_TYPE_STRING;
 995                pmsg->dli         = DLI_REG;
 996                pmsg->drv_id      = 0; /* id 0 - DIMAINT */
 997                pmsg->di_cpu      = 0;
 998                pmsg->data_length = len + 1;
 999
1000                memcpy(&pmsg[1], tmp, len + 1);
1001                queueCompleteMsg(pmsg);
1002                diva_maint_wakeup_read();
1003        }
1004
1005        org_mask = clients[id].Dbg.dbgMask;
1006        clients[id].Dbg.dbgMask = 0;
1007
1008        diva_os_leave_spin_lock(&dbg_q_lock, &old_irql, "register");
1009
1010        if (clients[id].request_pending) {
1011                clients[id].request_pending = 0;
1012                (*(clients[id].request))((ENTITY *)(*(clients[id].pIdiLib->DivaSTraceGetHandle))(clients[id].pIdiLib->hLib));
1013        }
1014
1015        diva_os_leave_spin_lock(&dbg_adapter_lock, &old_irql1, "register");
1016
1017        diva_set_driver_dbg_mask(id, org_mask);
1018}
1019
1020/*
1021  De-Register XDI adapter
1022*/
1023void diva_mnt_remove_xdi_adapter(const DESCRIPTOR *d) {
1024        diva_os_spin_lock_magic_t old_irql, old_irql1;
1025        dword sec, usec;
1026        int i;
1027        word size;
1028        byte *pmem = NULL;
1029
1030        diva_os_get_time(&sec, &usec);
1031
1032        diva_os_enter_spin_lock(&dbg_adapter_lock, &old_irql1, "read");
1033        diva_os_enter_spin_lock(&dbg_q_lock, &old_irql, "read");
1034
1035        for (i = 1; i < ARRAY_SIZE(clients); i++) {
1036                if (clients[i].hDbg && (clients[i].request == d->request)) {
1037                        diva_dbg_entry_head_t *pmsg;
1038                        char tmp[256];
1039                        int len;
1040
1041                        if (clients[i].pIdiLib) {
1042                                (*(clients[i].pIdiLib->DivaSTraceLibraryFinit))(clients[i].pIdiLib->hLib);
1043                                clients[i].pIdiLib = NULL;
1044
1045                                pmem = clients[i].pmem;
1046                                clients[i].pmem = NULL;
1047                        }
1048
1049                        clients[i].hDbg    = NULL;
1050                        clients[i].request_pending = 0;
1051                        if (clients[i].dma_handle >= 0) {
1052                                /*
1053                                  Free DMA handle
1054                                */
1055                                diva_free_dma_descriptor(clients[i].request, clients[i].dma_handle);
1056                                clients[i].dma_handle = -1;
1057                        }
1058                        clients[i].request = NULL;
1059
1060                        /*
1061                          Log driver register, MAINT driver ID is '0'
1062                        */
1063                        len = sprintf(tmp, "DIMAINT - drv # %d = '%s' de-registered",
1064                                      i, clients[i].Dbg.drvName);
1065
1066                        memset(&clients[i].Dbg, 0x00, sizeof(clients[i].Dbg));
1067
1068                        while (!(pmsg = (diva_dbg_entry_head_t *)queueAllocMsg(dbg_queue,
1069                                                                               (word)(len + 1 + sizeof(*pmsg))))) {
1070                                if ((pmsg = (diva_dbg_entry_head_t *)queuePeekMsg(dbg_queue, &size))) {
1071                                        queueFreeMsg(dbg_queue);
1072                                } else {
1073                                        break;
1074                                }
1075                        }
1076
1077                        if (pmsg) {
1078                                pmsg->sequence    = dbg_sequence++;
1079                                pmsg->time_sec    = sec;
1080                                pmsg->time_usec   = usec;
1081                                pmsg->facility    = MSG_TYPE_STRING;
1082                                pmsg->dli         = DLI_REG;
1083                                pmsg->drv_id      = 0; /* id 0 - DIMAINT */
1084                                pmsg->di_cpu      = 0;
1085                                pmsg->data_length = len + 1;
1086
1087                                memcpy(&pmsg[1], tmp, len + 1);
1088                                queueCompleteMsg(pmsg);
1089                                diva_maint_wakeup_read();
1090                        }
1091
1092                        break;
1093                }
1094        }
1095
1096        diva_os_leave_spin_lock(&dbg_q_lock, &old_irql, "read_ack");
1097        diva_os_leave_spin_lock(&dbg_adapter_lock, &old_irql1, "read_ack");
1098
1099        if (pmem) {
1100                diva_os_free(0, pmem);
1101        }
1102}
1103
1104/* ----------------------------------------------------------------
1105   Low level interface for management interface client
1106   ---------------------------------------------------------------- */
1107/*
1108  Return handle to client structure
1109*/
1110void *SuperTraceOpenAdapter(int AdapterNumber) {
1111        int i;
1112
1113        for (i = 1; i < ARRAY_SIZE(clients); i++) {
1114                if (clients[i].hDbg && clients[i].request && (clients[i].logical == AdapterNumber)) {
1115                        return (&clients[i]);
1116                }
1117        }
1118
1119        return NULL;
1120}
1121
1122int SuperTraceCloseAdapter(void *AdapterHandle) {
1123        return (0);
1124}
1125
1126int SuperTraceReadRequest(void *AdapterHandle, const char *name, byte *data) {
1127        diva_maint_client_t *pC = (diva_maint_client_t *)AdapterHandle;
1128
1129        if (pC && pC->pIdiLib && pC->request) {
1130                ENTITY *e = (ENTITY *)(*(pC->pIdiLib->DivaSTraceGetHandle))(pC->pIdiLib->hLib);
1131                byte *xdata = (byte *)&pC->xbuffer[0];
1132                char tmp = 0;
1133                word length;
1134
1135                if (!strcmp(name, "\\")) { /* Read ROOT */
1136                        name = &tmp;
1137                }
1138                length = SuperTraceCreateReadReq(xdata, name);
1139                single_p(xdata, &length, 0); /* End Of Message */
1140
1141                e->Req        = MAN_READ;
1142                e->ReqCh      = 0;
1143                e->X->PLength = length;
1144                e->X->P = (byte *)xdata;
1145
1146                pC->request_pending = 1;
1147
1148                return (0);
1149        }
1150
1151        return (-1);
1152}
1153
1154int SuperTraceGetNumberOfChannels(void *AdapterHandle) {
1155        if (AdapterHandle) {
1156                diva_maint_client_t *pC = (diva_maint_client_t *)AdapterHandle;
1157
1158                return (pC->channels);
1159        }
1160
1161        return (0);
1162}
1163
1164int SuperTraceASSIGN(void *AdapterHandle, byte *data) {
1165        diva_maint_client_t *pC = (diva_maint_client_t *)AdapterHandle;
1166
1167        if (pC && pC->pIdiLib && pC->request) {
1168                ENTITY *e = (ENTITY *)(*(pC->pIdiLib->DivaSTraceGetHandle))(pC->pIdiLib->hLib);
1169                IDI_SYNC_REQ *preq;
1170                char buffer[((sizeof(preq->xdi_extended_features) + 4) > sizeof(ENTITY)) ? (sizeof(preq->xdi_extended_features) + 4) : sizeof(ENTITY)];
1171                char features[4];
1172                word assign_data_length = 1;
1173
1174                features[0] = 0;
1175                pC->xbuffer[0] = 0;
1176                preq = (IDI_SYNC_REQ *)&buffer[0];
1177                preq->xdi_extended_features.Req = 0;
1178                preq->xdi_extended_features.Rc  = IDI_SYNC_REQ_XDI_GET_EXTENDED_FEATURES;
1179                preq->xdi_extended_features.info.buffer_length_in_bytes = sizeof(features);
1180                preq->xdi_extended_features.info.features = &features[0];
1181
1182                (*(pC->request))((ENTITY *)preq);
1183
1184                if ((features[0] & DIVA_XDI_EXTENDED_FEATURES_VALID) &&
1185                    (features[0] & DIVA_XDI_EXTENDED_FEATURE_MANAGEMENT_DMA)) {
1186                        dword uninitialized_var(rx_dma_magic);
1187                        if ((pC->dma_handle = diva_get_dma_descriptor(pC->request, &rx_dma_magic)) >= 0) {
1188                                pC->xbuffer[0] = LLI;
1189                                pC->xbuffer[1] = 8;
1190                                pC->xbuffer[2] = 0x40;
1191                                pC->xbuffer[3] = (byte)pC->dma_handle;
1192                                pC->xbuffer[4] = (byte)rx_dma_magic;
1193                                pC->xbuffer[5] = (byte)(rx_dma_magic >>  8);
1194                                pC->xbuffer[6] = (byte)(rx_dma_magic >> 16);
1195                                pC->xbuffer[7] = (byte)(rx_dma_magic >> 24);
1196                                pC->xbuffer[8] = (byte)(DIVA_MAX_MANAGEMENT_TRANSFER_SIZE & 0xFF);
1197                                pC->xbuffer[9] = (byte)(DIVA_MAX_MANAGEMENT_TRANSFER_SIZE >> 8);
1198                                pC->xbuffer[10] = 0;
1199
1200                                assign_data_length = 11;
1201                        }
1202                } else {
1203                        pC->dma_handle = -1;
1204                }
1205
1206                e->Id          = MAN_ID;
1207                e->callback    = diva_maint_xdi_cb;
1208                e->XNum        = 1;
1209                e->X           = &pC->XData;
1210                e->Req         = ASSIGN;
1211                e->ReqCh       = 0;
1212                e->X->PLength  = assign_data_length;
1213                e->X->P        = (byte *)&pC->xbuffer[0];
1214
1215                pC->request_pending = 1;
1216
1217                return (0);
1218        }
1219
1220        return (-1);
1221}
1222
1223int SuperTraceREMOVE(void *AdapterHandle) {
1224        diva_maint_client_t *pC = (diva_maint_client_t *)AdapterHandle;
1225
1226        if (pC && pC->pIdiLib && pC->request) {
1227                ENTITY *e = (ENTITY *)(*(pC->pIdiLib->DivaSTraceGetHandle))(pC->pIdiLib->hLib);
1228
1229                e->XNum        = 1;
1230                e->X           = &pC->XData;
1231                e->Req         = REMOVE;
1232                e->ReqCh       = 0;
1233                e->X->PLength  = 1;
1234                e->X->P        = (byte *)&pC->xbuffer[0];
1235                pC->xbuffer[0] = 0;
1236
1237                pC->request_pending = 1;
1238
1239                return (0);
1240        }
1241
1242        return (-1);
1243}
1244
1245int SuperTraceTraceOnRequest(void *hAdapter, const char *name, byte *data) {
1246        diva_maint_client_t *pC = (diva_maint_client_t *)hAdapter;
1247
1248        if (pC && pC->pIdiLib && pC->request) {
1249                ENTITY *e = (ENTITY *)(*(pC->pIdiLib->DivaSTraceGetHandle))(pC->pIdiLib->hLib);
1250                byte *xdata = (byte *)&pC->xbuffer[0];
1251                char tmp = 0;
1252                word length;
1253
1254                if (!strcmp(name, "\\")) { /* Read ROOT */
1255                        name = &tmp;
1256                }
1257                length = SuperTraceCreateReadReq(xdata, name);
1258                single_p(xdata, &length, 0); /* End Of Message */
1259                e->Req          = MAN_EVENT_ON;
1260                e->ReqCh        = 0;
1261                e->X->PLength   = length;
1262                e->X->P = (byte *)xdata;
1263
1264                pC->request_pending = 1;
1265
1266                return (0);
1267        }
1268
1269        return (-1);
1270}
1271
1272int SuperTraceWriteVar(void *AdapterHandle,
1273                       byte *data,
1274                       const char *name,
1275                       void *var,
1276                       byte type,
1277                       byte var_length) {
1278        diva_maint_client_t *pC = (diva_maint_client_t *)AdapterHandle;
1279
1280        if (pC && pC->pIdiLib && pC->request) {
1281                ENTITY *e = (ENTITY *)(*(pC->pIdiLib->DivaSTraceGetHandle))(pC->pIdiLib->hLib);
1282                diva_man_var_header_t *pVar = (diva_man_var_header_t *)&pC->xbuffer[0];
1283                word length = SuperTraceCreateReadReq((byte *)pVar, name);
1284
1285                memcpy(&pC->xbuffer[length], var, var_length);
1286                length += var_length;
1287                pVar->length += var_length;
1288                pVar->value_length = var_length;
1289                pVar->type = type;
1290                single_p((byte *)pVar, &length, 0); /* End Of Message */
1291
1292                e->Req = MAN_WRITE;
1293                e->ReqCh = 0;
1294                e->X->PLength   = length;
1295                e->X->P = (byte *)pVar;
1296
1297                pC->request_pending = 1;
1298
1299                return (0);
1300        }
1301
1302        return (-1);
1303}
1304
1305int SuperTraceExecuteRequest(void *AdapterHandle,
1306                             const char *name,
1307                             byte *data) {
1308        diva_maint_client_t *pC = (diva_maint_client_t *)AdapterHandle;
1309
1310        if (pC && pC->pIdiLib && pC->request) {
1311                ENTITY *e = (ENTITY *)(*(pC->pIdiLib->DivaSTraceGetHandle))(pC->pIdiLib->hLib);
1312                byte *xdata = (byte *)&pC->xbuffer[0];
1313                word length;
1314
1315                length = SuperTraceCreateReadReq(xdata, name);
1316                single_p(xdata, &length, 0); /* End Of Message */
1317
1318                e->Req = MAN_EXECUTE;
1319                e->ReqCh = 0;
1320                e->X->PLength = length;
1321                e->X->P = (byte *)xdata;
1322
1323                pC->request_pending = 1;
1324
1325                return (0);
1326        }
1327
1328        return (-1);
1329}
1330
1331static word SuperTraceCreateReadReq(byte *P, const char *path) {
1332        byte var_length;
1333        byte *plen;
1334
1335        var_length = (byte)strlen(path);
1336
1337        *P++ = ESC;
1338        plen = P++;
1339        *P++ = 0x80; /* MAN_IE */
1340        *P++ = 0x00; /* Type */
1341        *P++ = 0x00; /* Attribute */
1342        *P++ = 0x00; /* Status */
1343        *P++ = 0x00; /* Variable Length */
1344        *P++ = var_length;
1345        memcpy(P, path, var_length);
1346        P += var_length;
1347        *plen = var_length + 0x06;
1348
1349        return ((word)(var_length + 0x08));
1350}
1351
1352static void single_p(byte *P, word *PLength, byte Id) {
1353        P[(*PLength)++] = Id;
1354}
1355
1356static void diva_maint_xdi_cb(ENTITY *e) {
1357        diva_strace_context_t *pLib = DIVAS_CONTAINING_RECORD(e, diva_strace_context_t, e);
1358        diva_maint_client_t *pC;
1359        diva_os_spin_lock_magic_t old_irql, old_irql1;
1360
1361
1362        diva_os_enter_spin_lock(&dbg_adapter_lock, &old_irql1, "xdi_cb");
1363        diva_os_enter_spin_lock(&dbg_q_lock, &old_irql, "xdi_cb");
1364
1365        pC = (diva_maint_client_t *)pLib->hAdapter;
1366
1367        if ((e->complete == 255) || (pC->dma_handle < 0)) {
1368                if ((*(pLib->instance.DivaSTraceMessageInput))(&pLib->instance)) {
1369                        diva_mnt_internal_dprintf(0, DLI_ERR, "Trace internal library error");
1370                }
1371        } else {
1372                /*
1373                  Process combined management interface indication
1374                */
1375                if ((*(pLib->instance.DivaSTraceMessageInput))(&pLib->instance)) {
1376                        diva_mnt_internal_dprintf(0, DLI_ERR, "Trace internal library error (DMA mode)");
1377                }
1378        }
1379
1380        diva_os_leave_spin_lock(&dbg_q_lock, &old_irql, "xdi_cb");
1381
1382
1383        if (pC->request_pending) {
1384                pC->request_pending = 0;
1385                (*(pC->request))(e);
1386        }
1387
1388        diva_os_leave_spin_lock(&dbg_adapter_lock, &old_irql1, "xdi_cb");
1389}
1390
1391
1392static void diva_maint_error(void *user_context,
1393                             diva_strace_library_interface_t *hLib,
1394                             int Adapter,
1395                             int error,
1396                             const char *file,
1397                             int line) {
1398        diva_mnt_internal_dprintf(0, DLI_ERR,
1399                                  "Trace library error(%d) A(%d) %s %d", error, Adapter, file, line);
1400}
1401
1402static void print_ie(diva_trace_ie_t *ie, char *buffer, int length) {
1403        int i;
1404
1405        buffer[0] = 0;
1406
1407        if (length > 32) {
1408                for (i = 0; ((i < ie->length) && (length > 3)); i++) {
1409                        sprintf(buffer, "%02x", ie->data[i]);
1410                        buffer += 2;
1411                        length -= 2;
1412                        if (i < (ie->length - 1)) {
1413                                strcpy(buffer, " ");
1414                                buffer++;
1415                                length--;
1416                        }
1417                }
1418        }
1419}
1420
1421static void diva_maint_state_change_notify(void *user_context,
1422                                           diva_strace_library_interface_t *hLib,
1423                                           int Adapter,
1424                                           diva_trace_line_state_t *channel,
1425                                           int notify_subject) {
1426        diva_maint_client_t *pC = (diva_maint_client_t *)user_context;
1427        diva_trace_fax_state_t *fax = &channel->fax;
1428        diva_trace_modem_state_t *modem = &channel->modem;
1429        char tmp[256];
1430
1431        if (!pC->hDbg) {
1432                return;
1433        }
1434
1435        switch (notify_subject) {
1436        case DIVA_SUPER_TRACE_NOTIFY_LINE_CHANGE: {
1437                int view = (TraceFilter[0] == 0);
1438                /*
1439                  Process selective Trace
1440                */
1441                if (channel->Line[0] == 'I' && channel->Line[1] == 'd' &&
1442                    channel->Line[2] == 'l' && channel->Line[3] == 'e') {
1443                        if ((TraceFilterIdent == pC->hDbg->id) && (TraceFilterChannel == (int)channel->ChannelNumber)) {
1444                                (*(hLib->DivaSTraceSetBChannel))(hLib, (int)channel->ChannelNumber, 0);
1445                                (*(hLib->DivaSTraceSetAudioTap))(hLib, (int)channel->ChannelNumber, 0);
1446                                diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG, "Selective Trace OFF for Ch=%d",
1447                                                          (int)channel->ChannelNumber);
1448                                TraceFilterIdent   = -1;
1449                                TraceFilterChannel = -1;
1450                                view = 1;
1451                        }
1452                } else if (TraceFilter[0] && (TraceFilterIdent < 0) && !(diva_mnt_cmp_nmbr(&channel->RemoteAddress[0]) &&
1453                                                                         diva_mnt_cmp_nmbr(&channel->LocalAddress[0]))) {
1454
1455                        if ((pC->hDbg->dbgMask & DIVA_MGT_DBG_IFC_BCHANNEL) != 0) { /* Activate B-channel trace */
1456                                (*(hLib->DivaSTraceSetBChannel))(hLib, (int)channel->ChannelNumber, 1);
1457                        }
1458                        if ((pC->hDbg->dbgMask & DIVA_MGT_DBG_IFC_AUDIO) != 0) { /* Activate AudioTap Trace */
1459                                (*(hLib->DivaSTraceSetAudioTap))(hLib, (int)channel->ChannelNumber, 1);
1460                        }
1461
1462                        TraceFilterIdent   = pC->hDbg->id;
1463                        TraceFilterChannel = (int)channel->ChannelNumber;
1464
1465                        if (TraceFilterIdent >= 0) {
1466                                diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG, "Selective Trace ON for Ch=%d",
1467                                                          (int)channel->ChannelNumber);
1468                                view = 1;
1469                        }
1470                }
1471                if (view && (pC->hDbg->dbgMask & DIVA_MGT_DBG_LINE_EVENTS)) {
1472                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "L Ch     = %d",
1473                                                  (int)channel->ChannelNumber);
1474                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "L Status = <%s>", &channel->Line[0]);
1475                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "L Layer1 = <%s>", &channel->Framing[0]);
1476                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "L Layer2 = <%s>", &channel->Layer2[0]);
1477                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "L Layer3 = <%s>", &channel->Layer3[0]);
1478                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "L RAddr  = <%s>",
1479                                                  &channel->RemoteAddress[0]);
1480                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "L RSAddr = <%s>",
1481                                                  &channel->RemoteSubAddress[0]);
1482                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "L LAddr  = <%s>",
1483                                                  &channel->LocalAddress[0]);
1484                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "L LSAddr = <%s>",
1485                                                  &channel->LocalSubAddress[0]);
1486                        print_ie(&channel->call_BC, tmp, sizeof(tmp));
1487                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "L BC     = <%s>", tmp);
1488                        print_ie(&channel->call_HLC, tmp, sizeof(tmp));
1489                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "L HLC    = <%s>", tmp);
1490                        print_ie(&channel->call_LLC, tmp, sizeof(tmp));
1491                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "L LLC    = <%s>", tmp);
1492                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "L CR     = 0x%x", channel->CallReference);
1493                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "L Disc   = 0x%x",
1494                                                  channel->LastDisconnecCause);
1495                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "L Owner  = <%s>", &channel->UserID[0]);
1496                }
1497
1498        } break;
1499
1500        case DIVA_SUPER_TRACE_NOTIFY_MODEM_CHANGE:
1501                if (pC->hDbg->dbgMask & DIVA_MGT_DBG_MDM_PROGRESS) {
1502                        {
1503                                int ch = TraceFilterChannel;
1504                                int id = TraceFilterIdent;
1505
1506                                if ((id >= 0) && (ch >= 0) && (id < ARRAY_SIZE(clients)) &&
1507                                    (clients[id].Dbg.id == (byte)id) && (clients[id].pIdiLib == hLib)) {
1508                                        if (ch != (int)modem->ChannelNumber) {
1509                                                break;
1510                                        }
1511                                } else if (TraceFilter[0] != 0) {
1512                                        break;
1513                                }
1514                        }
1515
1516
1517                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM Ch    = %lu",
1518                                                  (int)modem->ChannelNumber);
1519                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM Event = %lu", modem->Event);
1520                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM Norm  = %lu", modem->Norm);
1521                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM Opts. = 0x%08x", modem->Options);
1522                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM Tx    = %lu Bps", modem->TxSpeed);
1523                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM Rx    = %lu Bps", modem->RxSpeed);
1524                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM RT    = %lu mSec",
1525                                                  modem->RoundtripMsec);
1526                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM Sr    = %lu", modem->SymbolRate);
1527                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM Rxl   = %d dBm", modem->RxLeveldBm);
1528                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM El    = %d dBm", modem->EchoLeveldBm);
1529                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM SNR   = %lu dB", modem->SNRdb);
1530                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM MAE   = %lu", modem->MAE);
1531                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM LRet  = %lu",
1532                                                  modem->LocalRetrains);
1533                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM RRet  = %lu",
1534                                                  modem->RemoteRetrains);
1535                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM LRes  = %lu", modem->LocalResyncs);
1536                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM RRes  = %lu",
1537                                                  modem->RemoteResyncs);
1538                        if (modem->Event == 3) {
1539                                diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "MDM Disc  =  %lu", modem->DiscReason);
1540                        }
1541                }
1542                if ((modem->Event == 3) && (pC->hDbg->dbgMask & DIVA_MGT_DBG_MDM_STATISTICS)) {
1543                        (*(pC->pIdiLib->DivaSTraceGetModemStatistics))(pC->pIdiLib);
1544                }
1545                break;
1546
1547        case DIVA_SUPER_TRACE_NOTIFY_FAX_CHANGE:
1548                if (pC->hDbg->dbgMask & DIVA_MGT_DBG_FAX_PROGRESS) {
1549                        {
1550                                int ch = TraceFilterChannel;
1551                                int id = TraceFilterIdent;
1552
1553                                if ((id >= 0) && (ch >= 0) && (id < ARRAY_SIZE(clients)) &&
1554                                    (clients[id].Dbg.id == (byte)id) && (clients[id].pIdiLib == hLib)) {
1555                                        if (ch != (int)fax->ChannelNumber) {
1556                                                break;
1557                                        }
1558                                } else if (TraceFilter[0] != 0) {
1559                                        break;
1560                                }
1561                        }
1562
1563                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Ch    = %lu", (int)fax->ChannelNumber);
1564                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Event = %lu",     fax->Event);
1565                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Pages = %lu",     fax->Page_Counter);
1566                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Feat. = 0x%08x",  fax->Features);
1567                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX ID    = <%s>",    &fax->Station_ID[0]);
1568                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Saddr = <%s>",    &fax->Subaddress[0]);
1569                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Pwd   = <%s>",    &fax->Password[0]);
1570                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Speed = %lu",     fax->Speed);
1571                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Res.  = 0x%08x",  fax->Resolution);
1572                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Width = %lu",     fax->Paper_Width);
1573                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Length= %lu",     fax->Paper_Length);
1574                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX SLT   = %lu",     fax->Scanline_Time);
1575                        if (fax->Event == 3) {
1576                                diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT, "FAX Disc  = %lu",     fax->Disc_Reason);
1577                        }
1578                }
1579                if ((fax->Event == 3) && (pC->hDbg->dbgMask & DIVA_MGT_DBG_FAX_STATISTICS)) {
1580                        (*(pC->pIdiLib->DivaSTraceGetFaxStatistics))(pC->pIdiLib);
1581                }
1582                break;
1583
1584        case DIVA_SUPER_TRACE_INTERFACE_CHANGE:
1585                if (pC->hDbg->dbgMask & DIVA_MGT_DBG_IFC_EVENTS) {
1586                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT,
1587                                                  "Layer 1 -> [%s]", channel->pInterface->Layer1);
1588                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_STAT,
1589                                                  "Layer 2 -> [%s]", channel->pInterface->Layer2);
1590                }
1591                break;
1592
1593        case DIVA_SUPER_TRACE_NOTIFY_STAT_CHANGE:
1594                if (pC->hDbg->dbgMask & DIVA_MGT_DBG_IFC_STATISTICS) {
1595                        /*
1596                          Incoming Statistics
1597                        */
1598                        if (channel->pInterfaceStat->inc.Calls) {
1599                                diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1600                                                          "Inc Calls                     =%lu", channel->pInterfaceStat->inc.Calls);
1601                        }
1602                        if (channel->pInterfaceStat->inc.Connected) {
1603                                diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1604                                                          "Inc Connected                 =%lu", channel->pInterfaceStat->inc.Connected);
1605                        }
1606                        if (channel->pInterfaceStat->inc.User_Busy) {
1607                                diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1608                                                          "Inc Busy                      =%lu", channel->pInterfaceStat->inc.User_Busy);
1609                        }
1610                        if (channel->pInterfaceStat->inc.Call_Rejected) {
1611                                diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1612                                                          "Inc Rejected                  =%lu", channel->pInterfaceStat->inc.Call_Rejected);
1613                        }
1614                        if (channel->pInterfaceStat->inc.Wrong_Number) {
1615                                diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1616                                                          "Inc Wrong Nr                  =%lu", channel->pInterfaceStat->inc.Wrong_Number);
1617                        }
1618                        if (channel->pInterfaceStat->inc.Incompatible_Dst) {
1619                                diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1620                                                          "Inc Incomp. Dest              =%lu", channel->pInterfaceStat->inc.Incompatible_Dst);
1621                        }
1622                        if (channel->pInterfaceStat->inc.Out_of_Order) {
1623                                diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1624                                                          "Inc Out of Order              =%lu", channel->pInterfaceStat->inc.Out_of_Order);
1625                        }
1626                        if (channel->pInterfaceStat->inc.Ignored) {
1627                                diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1628                                                          "Inc Ignored                   =%lu", channel->pInterfaceStat->inc.Ignored);
1629                        }
1630
1631                        /*
1632                          Outgoing Statistics
1633                        */
1634                        if (channel->pInterfaceStat->outg.Calls) {
1635                                diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1636                                                          "Outg Calls                    =%lu", channel->pInterfaceStat->outg.Calls);
1637                        }
1638                        if (channel->pInterfaceStat->outg.Connected) {
1639                                diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1640                                                          "Outg Connected                =%lu", channel->pInterfaceStat->outg.Connected);
1641                        }
1642                        if (channel->pInterfaceStat->outg.User_Busy) {
1643                                diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1644                                                          "Outg Busy                     =%lu", channel->pInterfaceStat->outg.User_Busy);
1645                        }
1646                        if (channel->pInterfaceStat->outg.No_Answer) {
1647                                diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1648                                                          "Outg No Answer                =%lu", channel->pInterfaceStat->outg.No_Answer);
1649                        }
1650                        if (channel->pInterfaceStat->outg.Wrong_Number) {
1651                                diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1652                                                          "Outg Wrong Nr                 =%lu", channel->pInterfaceStat->outg.Wrong_Number);
1653                        }
1654                        if (channel->pInterfaceStat->outg.Call_Rejected) {
1655                                diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1656                                                          "Outg Rejected                 =%lu", channel->pInterfaceStat->outg.Call_Rejected);
1657                        }
1658                        if (channel->pInterfaceStat->outg.Other_Failures) {
1659                                diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1660                                                          "Outg Other Failures           =%lu", channel->pInterfaceStat->outg.Other_Failures);
1661                        }
1662                }
1663                break;
1664
1665        case DIVA_SUPER_TRACE_NOTIFY_MDM_STAT_CHANGE:
1666                if (channel->pInterfaceStat->mdm.Disc_Normal) {
1667                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1668                                                  "MDM Disc Normal        = %lu", channel->pInterfaceStat->mdm.Disc_Normal);
1669                }
1670                if (channel->pInterfaceStat->mdm.Disc_Unspecified) {
1671                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1672                                                  "MDM Disc Unsp.         = %lu", channel->pInterfaceStat->mdm.Disc_Unspecified);
1673                }
1674                if (channel->pInterfaceStat->mdm.Disc_Busy_Tone) {
1675                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1676                                                  "MDM Disc Busy Tone     = %lu", channel->pInterfaceStat->mdm.Disc_Busy_Tone);
1677                }
1678                if (channel->pInterfaceStat->mdm.Disc_Congestion) {
1679                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1680                                                  "MDM Disc Congestion    = %lu", channel->pInterfaceStat->mdm.Disc_Congestion);
1681                }
1682                if (channel->pInterfaceStat->mdm.Disc_Carr_Wait) {
1683                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1684                                                  "MDM Disc Carrier Wait  = %lu", channel->pInterfaceStat->mdm.Disc_Carr_Wait);
1685                }
1686                if (channel->pInterfaceStat->mdm.Disc_Trn_Timeout) {
1687                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1688                                                  "MDM Disc Trn. T.o.     = %lu", channel->pInterfaceStat->mdm.Disc_Trn_Timeout);
1689                }
1690                if (channel->pInterfaceStat->mdm.Disc_Incompat) {
1691                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1692                                                  "MDM Disc Incompatible  = %lu", channel->pInterfaceStat->mdm.Disc_Incompat);
1693                }
1694                if (channel->pInterfaceStat->mdm.Disc_Frame_Rej) {
1695                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1696                                                  "MDM Disc Frame Reject  = %lu", channel->pInterfaceStat->mdm.Disc_Frame_Rej);
1697                }
1698                if (channel->pInterfaceStat->mdm.Disc_V42bis) {
1699                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1700                                                  "MDM Disc V.42bis       = %lu", channel->pInterfaceStat->mdm.Disc_V42bis);
1701                }
1702                break;
1703
1704        case DIVA_SUPER_TRACE_NOTIFY_FAX_STAT_CHANGE:
1705                if (channel->pInterfaceStat->fax.Disc_Normal) {
1706                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1707                                                  "FAX Disc Normal        = %lu", channel->pInterfaceStat->fax.Disc_Normal);
1708                }
1709                if (channel->pInterfaceStat->fax.Disc_Not_Ident) {
1710                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1711                                                  "FAX Disc Not Ident.    = %lu", channel->pInterfaceStat->fax.Disc_Not_Ident);
1712                }
1713                if (channel->pInterfaceStat->fax.Disc_No_Response) {
1714                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1715                                                  "FAX Disc No Response   = %lu", channel->pInterfaceStat->fax.Disc_No_Response);
1716                }
1717                if (channel->pInterfaceStat->fax.Disc_Retries) {
1718                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1719                                                  "FAX Disc Max Retries   = %lu", channel->pInterfaceStat->fax.Disc_Retries);
1720                }
1721                if (channel->pInterfaceStat->fax.Disc_Unexp_Msg) {
1722                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1723                                                  "FAX Unexp. Msg.        = %lu", channel->pInterfaceStat->fax.Disc_Unexp_Msg);
1724                }
1725                if (channel->pInterfaceStat->fax.Disc_No_Polling) {
1726                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1727                                                  "FAX Disc No Polling    = %lu", channel->pInterfaceStat->fax.Disc_No_Polling);
1728                }
1729                if (channel->pInterfaceStat->fax.Disc_Training) {
1730                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1731                                                  "FAX Disc Training      = %lu", channel->pInterfaceStat->fax.Disc_Training);
1732                }
1733                if (channel->pInterfaceStat->fax.Disc_Unexpected) {
1734                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1735                                                  "FAX Disc Unexpected    = %lu", channel->pInterfaceStat->fax.Disc_Unexpected);
1736                }
1737                if (channel->pInterfaceStat->fax.Disc_Application) {
1738                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1739                                                  "FAX Disc Application   = %lu", channel->pInterfaceStat->fax.Disc_Application);
1740                }
1741                if (channel->pInterfaceStat->fax.Disc_Incompat) {
1742                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1743                                                  "FAX Disc Incompatible  = %lu", channel->pInterfaceStat->fax.Disc_Incompat);
1744                }
1745                if (channel->pInterfaceStat->fax.Disc_No_Command) {
1746                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1747                                                  "FAX Disc No Command    = %lu", channel->pInterfaceStat->fax.Disc_No_Command);
1748                }
1749                if (channel->pInterfaceStat->fax.Disc_Long_Msg) {
1750                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1751                                                  "FAX Disc Long Msg.     = %lu", channel->pInterfaceStat->fax.Disc_Long_Msg);
1752                }
1753                if (channel->pInterfaceStat->fax.Disc_Supervisor) {
1754                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1755                                                  "FAX Disc Supervisor    = %lu", channel->pInterfaceStat->fax.Disc_Supervisor);
1756                }
1757                if (channel->pInterfaceStat->fax.Disc_SUB_SEP_PWD) {
1758                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1759                                                  "FAX Disc SUP SEP PWD   = %lu", channel->pInterfaceStat->fax.Disc_SUB_SEP_PWD);
1760                }
1761                if (channel->pInterfaceStat->fax.Disc_Invalid_Msg) {
1762                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1763                                                  "FAX Disc Invalid Msg.  = %lu", channel->pInterfaceStat->fax.Disc_Invalid_Msg);
1764                }
1765                if (channel->pInterfaceStat->fax.Disc_Page_Coding) {
1766                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1767                                                  "FAX Disc Page Coding   = %lu", channel->pInterfaceStat->fax.Disc_Page_Coding);
1768                }
1769                if (channel->pInterfaceStat->fax.Disc_App_Timeout) {
1770                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1771                                                  "FAX Disc Appl. T.o.    = %lu", channel->pInterfaceStat->fax.Disc_App_Timeout);
1772                }
1773                if (channel->pInterfaceStat->fax.Disc_Unspecified) {
1774                        diva_mnt_internal_dprintf(pC->hDbg->id, DLI_LOG,
1775                                                  "FAX Disc Unspec.       = %lu", channel->pInterfaceStat->fax.Disc_Unspecified);
1776                }
1777                break;
1778        }
1779}
1780
1781/*
1782  Receive trace information from the Management Interface and store it in the
1783  internal trace buffer with MSG_TYPE_MLOG as is, without any filtering.
1784  Event Filtering and formatting is done in  Management Interface self.
1785*/
1786static void diva_maint_trace_notify(void *user_context,
1787                                    diva_strace_library_interface_t *hLib,
1788                                    int Adapter,
1789                                    void *xlog_buffer,
1790                                    int length) {
1791        diva_maint_client_t *pC = (diva_maint_client_t *)user_context;
1792        diva_dbg_entry_head_t *pmsg;
1793        word size;
1794        dword sec, usec;
1795        int ch = TraceFilterChannel;
1796        int id = TraceFilterIdent;
1797
1798        /*
1799          Selective trace
1800        */
1801        if ((id >= 0) && (ch >= 0) && (id < ARRAY_SIZE(clients)) &&
1802            (clients[id].Dbg.id == (byte)id) && (clients[id].pIdiLib == hLib)) {
1803                const char *p = NULL;
1804                int ch_value = -1;
1805                MI_XLOG_HDR *TrcData = (MI_XLOG_HDR *)xlog_buffer;
1806
1807                if (Adapter != clients[id].logical) {
1808                        return; /* Ignore all trace messages from other adapters */
1809                }
1810
1811                if (TrcData->code == 24) {
1812                        p = (char *)&TrcData->code;
1813                        p += 2;
1814                }
1815
1816                /*
1817                  All L1 messages start as [dsp,ch], so we can filter this information
1818                  and filter out all messages that use different channel
1819                */
1820                if (p && p[0] == '[') {
1821                        if (p[2] == ',') {
1822                                p += 3;
1823                                ch_value = *p - '0';
1824                        } else if (p[3] == ',') {
1825                                p += 4;
1826                                ch_value = *p - '0';
1827                        }
1828                        if (ch_value >= 0) {
1829                                if (p[2] == ']') {
1830                                        ch_value = ch_value * 10 + p[1] - '0';
1831                                }
1832                                if (ch_value != ch) {
1833                                        return; /* Ignore other channels */
1834                                }
1835                        }
1836                }
1837
1838        } else if (TraceFilter[0] != 0) {
1839                return; /* Ignore trace if trace filter is activated, but idle */
1840        }
1841
1842        diva_os_get_time(&sec, &usec);
1843
1844        while (!(pmsg = (diva_dbg_entry_head_t *)queueAllocMsg(dbg_queue,
1845                                                               (word)length + sizeof(*pmsg)))) {
1846                if ((pmsg = (diva_dbg_entry_head_t *)queuePeekMsg(dbg_queue, &size))) {
1847                        queueFreeMsg(dbg_queue);
1848                } else {
1849                        break;
1850                }
1851        }
1852        if (pmsg) {
1853                memcpy(&pmsg[1], xlog_buffer, length);
1854                pmsg->sequence    = dbg_sequence++;
1855                pmsg->time_sec    = sec;
1856                pmsg->time_usec   = usec;
1857                pmsg->facility    = MSG_TYPE_MLOG;
1858                pmsg->dli         = pC->logical;
1859                pmsg->drv_id      = pC->hDbg->id;
1860                pmsg->di_cpu      = 0;
1861                pmsg->data_length = length;
1862                queueCompleteMsg(pmsg);
1863                if (queueCount(dbg_queue)) {
1864                        diva_maint_wakeup_read();
1865                }
1866        }
1867}
1868
1869
1870/*
1871  Convert MAINT trace mask to management interface trace mask/work/facility and
1872  issue command to management interface
1873*/
1874static void diva_change_management_debug_mask(diva_maint_client_t *pC, dword old_mask) {
1875        if (pC->request && pC->hDbg && pC->pIdiLib) {
1876                dword changed = pC->hDbg->dbgMask ^ old_mask;
1877
1878                if (changed & DIVA_MGT_DBG_TRACE) {
1879                        (*(pC->pIdiLib->DivaSTraceSetInfo))(pC->pIdiLib,
1880                                                            (pC->hDbg->dbgMask & DIVA_MGT_DBG_TRACE) != 0);
1881                }
1882                if (changed & DIVA_MGT_DBG_DCHAN) {
1883                        (*(pC->pIdiLib->DivaSTraceSetDChannel))(pC->pIdiLib,
1884                                                                (pC->hDbg->dbgMask & DIVA_MGT_DBG_DCHAN) != 0);
1885                }
1886                if (!TraceFilter[0]) {
1887                        if (changed & DIVA_MGT_DBG_IFC_BCHANNEL) {
1888                                int i, state = ((pC->hDbg->dbgMask & DIVA_MGT_DBG_IFC_BCHANNEL) != 0);
1889
1890                                for (i = 0; i < pC->channels; i++) {
1891                                        (*(pC->pIdiLib->DivaSTraceSetBChannel))(pC->pIdiLib, i + 1, state);
1892                                }
1893                        }
1894                        if (changed & DIVA_MGT_DBG_IFC_AUDIO) {
1895                                int i, state = ((pC->hDbg->dbgMask & DIVA_MGT_DBG_IFC_AUDIO) != 0);
1896
1897                                for (i = 0; i < pC->channels; i++) {
1898                                        (*(pC->pIdiLib->DivaSTraceSetAudioTap))(pC->pIdiLib, i + 1, state);
1899                                }
1900                        }
1901                }
1902        }
1903}
1904
1905
1906void diva_mnt_internal_dprintf(dword drv_id, dword type, char *fmt, ...) {
1907        va_list ap;
1908
1909        va_start(ap, fmt);
1910        DI_format(0, (word)drv_id, (int)type, fmt, ap);
1911        va_end(ap);
1912}
1913
1914/*
1915  Shutdown all adapters before driver removal
1916*/
1917int diva_mnt_shutdown_xdi_adapters(void) {
1918        diva_os_spin_lock_magic_t old_irql, old_irql1;
1919        int i, fret = 0;
1920        byte *pmem;
1921
1922
1923        for (i = 1; i < ARRAY_SIZE(clients); i++) {
1924                pmem = NULL;
1925
1926                diva_os_enter_spin_lock(&dbg_adapter_lock, &old_irql1, "unload");
1927                diva_os_enter_spin_lock(&dbg_q_lock, &old_irql, "unload");
1928
1929                if (clients[i].hDbg && clients[i].pIdiLib && clients[i].request) {
1930                        if ((*(clients[i].pIdiLib->DivaSTraceLibraryStop))(clients[i].pIdiLib) == 1) {
1931                                /*
1932                                  Adapter removal complete
1933                                */
1934                                if (clients[i].pIdiLib) {
1935                                        (*(clients[i].pIdiLib->DivaSTraceLibraryFinit))(clients[i].pIdiLib->hLib);
1936                                        clients[i].pIdiLib = NULL;
1937
1938                                        pmem = clients[i].pmem;
1939                                        clients[i].pmem = NULL;
1940                                }
1941                                clients[i].hDbg    = NULL;
1942                                clients[i].request_pending = 0;
1943
1944                                if (clients[i].dma_handle >= 0) {
1945                                        /*
1946                                          Free DMA handle
1947                                        */
1948                                        diva_free_dma_descriptor(clients[i].request, clients[i].dma_handle);
1949                                        clients[i].dma_handle = -1;
1950                                }
1951                                clients[i].request = NULL;
1952                        } else {
1953                                fret = -1;
1954                        }
1955                }
1956
1957                diva_os_leave_spin_lock(&dbg_q_lock, &old_irql, "unload");
1958                if (clients[i].hDbg && clients[i].pIdiLib && clients[i].request && clients[i].request_pending) {
1959                        clients[i].request_pending = 0;
1960                        (*(clients[i].request))((ENTITY *)(*(clients[i].pIdiLib->DivaSTraceGetHandle))(clients[i].pIdiLib->hLib));
1961                        if (clients[i].dma_handle >= 0) {
1962                                diva_free_dma_descriptor(clients[i].request, clients[i].dma_handle);
1963                                clients[i].dma_handle = -1;
1964                        }
1965                }
1966                diva_os_leave_spin_lock(&dbg_adapter_lock, &old_irql1, "unload");
1967
1968                if (pmem) {
1969                        diva_os_free(0, pmem);
1970                }
1971        }
1972
1973        return (fret);
1974}
1975
1976/*
1977  Set/Read the trace filter used for selective tracing.
1978  Affects B- and Audio Tap trace mask at run time
1979*/
1980int diva_set_trace_filter(int filter_length, const char *filter) {
1981        diva_os_spin_lock_magic_t old_irql, old_irql1;
1982        int i, ch, on, client_b_on, client_atap_on;
1983
1984        diva_os_enter_spin_lock(&dbg_adapter_lock, &old_irql1, "dbg mask");
1985        diva_os_enter_spin_lock(&dbg_q_lock, &old_irql, "write_filter");
1986
1987        if (filter_length <= DIVA_MAX_SELECTIVE_FILTER_LENGTH) {
1988                memcpy(&TraceFilter[0], filter, filter_length);
1989                if (TraceFilter[filter_length]) {
1990                        TraceFilter[filter_length] = 0;
1991                }
1992                if (TraceFilter[0] == '*') {
1993                        TraceFilter[0] = 0;
1994                }
1995        } else {
1996                filter_length = -1;
1997        }
1998
1999        TraceFilterIdent   = -1;
2000        TraceFilterChannel = -1;
2001
2002        on = (TraceFilter[0] == 0);
2003
2004        for (i = 1; i < ARRAY_SIZE(clients); i++) {
2005                if (clients[i].hDbg && clients[i].pIdiLib && clients[i].request) {
2006                        client_b_on    = on && ((clients[i].hDbg->dbgMask & DIVA_MGT_DBG_IFC_BCHANNEL) != 0);
2007                        client_atap_on = on && ((clients[i].hDbg->dbgMask & DIVA_MGT_DBG_IFC_AUDIO)    != 0);
2008                        for (ch = 0; ch < clients[i].channels; ch++) {
2009                                (*(clients[i].pIdiLib->DivaSTraceSetBChannel))(clients[i].pIdiLib->hLib, ch + 1, client_b_on);
2010                                (*(clients[i].pIdiLib->DivaSTraceSetAudioTap))(clients[i].pIdiLib->hLib, ch + 1, client_atap_on);
2011                        }
2012                }
2013        }
2014
2015        for (i = 1; i < ARRAY_SIZE(clients); i++) {
2016                if (clients[i].hDbg && clients[i].pIdiLib && clients[i].request && clients[i].request_pending) {
2017                        diva_os_leave_spin_lock(&dbg_q_lock, &old_irql, "write_filter");
2018                        clients[i].request_pending = 0;
2019                        (*(clients[i].request))((ENTITY *)(*(clients[i].pIdiLib->DivaSTraceGetHandle))(clients[i].pIdiLib->hLib));
2020                        diva_os_enter_spin_lock(&dbg_q_lock, &old_irql, "write_filter");
2021                }
2022        }
2023
2024        diva_os_leave_spin_lock(&dbg_q_lock, &old_irql, "write_filter");
2025        diva_os_leave_spin_lock(&dbg_adapter_lock, &old_irql1, "dbg mask");
2026
2027        return (filter_length);
2028}
2029
2030int diva_get_trace_filter(int max_length, char *filter) {
2031        diva_os_spin_lock_magic_t old_irql;
2032        int len;
2033
2034        diva_os_enter_spin_lock(&dbg_q_lock, &old_irql, "read_filter");
2035        len = strlen(&TraceFilter[0]) + 1;
2036        if (max_length >= len) {
2037                memcpy(filter, &TraceFilter[0], len);
2038        }
2039        diva_os_leave_spin_lock(&dbg_q_lock, &old_irql, "read_filter");
2040
2041        return (len);
2042}
2043
2044static int diva_dbg_cmp_key(const char *ref, const char *key) {
2045        while (*key && (*ref++ == *key++));
2046        return (!*key && !*ref);
2047}
2048
2049/*
2050  In case trace filter starts with "C" character then
2051  all following characters are interpreted as command.
2052  Followings commands are available:
2053  - single, trace single call at time, independent from CPN/CiPN
2054*/
2055static int diva_mnt_cmp_nmbr(const char *nmbr) {
2056        const char *ref = &TraceFilter[0];
2057        int ref_len = strlen(&TraceFilter[0]), nmbr_len = strlen(nmbr);
2058
2059        if (ref[0] == 'C') {
2060                if (diva_dbg_cmp_key(&ref[1], "single")) {
2061                        return (0);
2062                }
2063                return (-1);
2064        }
2065
2066        if (!ref_len || (ref_len > nmbr_len)) {
2067                return (-1);
2068        }
2069
2070        nmbr = nmbr + nmbr_len - 1;
2071        ref  = ref  + ref_len  - 1;
2072
2073        while (ref_len--) {
2074                if (*nmbr-- != *ref--) {
2075                        return (-1);
2076                }
2077        }
2078
2079        return (0);
2080}
2081
2082static int diva_get_dma_descriptor(IDI_CALL request, dword *dma_magic) {
2083        ENTITY e;
2084        IDI_SYNC_REQ *pReq = (IDI_SYNC_REQ *)&e;
2085
2086        if (!request) {
2087                return (-1);
2088        }
2089
2090        pReq->xdi_dma_descriptor_operation.Req = 0;
2091        pReq->xdi_dma_descriptor_operation.Rc = IDI_SYNC_REQ_DMA_DESCRIPTOR_OPERATION;
2092
2093        pReq->xdi_dma_descriptor_operation.info.operation =     IDI_SYNC_REQ_DMA_DESCRIPTOR_ALLOC;
2094        pReq->xdi_dma_descriptor_operation.info.descriptor_number  = -1;
2095        pReq->xdi_dma_descriptor_operation.info.descriptor_address = NULL;
2096        pReq->xdi_dma_descriptor_operation.info.descriptor_magic   = 0;
2097
2098        (*request)((ENTITY *)pReq);
2099
2100        if (!pReq->xdi_dma_descriptor_operation.info.operation &&
2101            (pReq->xdi_dma_descriptor_operation.info.descriptor_number >= 0) &&
2102            pReq->xdi_dma_descriptor_operation.info.descriptor_magic) {
2103                *dma_magic = pReq->xdi_dma_descriptor_operation.info.descriptor_magic;
2104                return (pReq->xdi_dma_descriptor_operation.info.descriptor_number);
2105        } else {
2106                return (-1);
2107        }
2108}
2109
2110static void diva_free_dma_descriptor(IDI_CALL request, int nr) {
2111        ENTITY e;
2112        IDI_SYNC_REQ *pReq = (IDI_SYNC_REQ *)&e;
2113
2114        if (!request || (nr < 0)) {
2115                return;
2116        }
2117
2118        pReq->xdi_dma_descriptor_operation.Req = 0;
2119        pReq->xdi_dma_descriptor_operation.Rc = IDI_SYNC_REQ_DMA_DESCRIPTOR_OPERATION;
2120
2121        pReq->xdi_dma_descriptor_operation.info.operation = IDI_SYNC_REQ_DMA_DESCRIPTOR_FREE;
2122        pReq->xdi_dma_descriptor_operation.info.descriptor_number  = nr;
2123        pReq->xdi_dma_descriptor_operation.info.descriptor_address = NULL;
2124        pReq->xdi_dma_descriptor_operation.info.descriptor_magic   = 0;
2125
2126        (*request)((ENTITY *)pReq);
2127}
2128